題目描述(中等難度)
算法1
(前綴和)
一開始先寫了個三重循環,然後暴力算 i 到 j - 1 和 j 到 k 的異或結果,提交了下發現超時,後來想到了可以用前綴和來優化 (利用性質(a ^ b) ^ a = b;
),最後順利 AC 了這個題
時間複雜度是,空間複雜度是
C++代碼
class Solution {
public:
// 前綴和思想 (a ^ b) ^ a = b;
int v[307];
int countTriplets(vector<int> &arr) {
int n = arr.size(), cnt = 0;
v[0] = 0;
for (int i = 1; i <= n; i ++) {
v[i] = v[i - 1] ^ arr[i - 1]; // 下標存 1 開始,arr[i - 1]是第 i 個數
}
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j; k < n; k++) {
if ((v[i] ^ v[j]) == (v[j] ^ v[k + 1])) cnt ++;
}
}
}
return cnt;
}
};
算法2
(位運算優化)
算法 1 是利用了(a ^ b) ^ a = b;
,藉助前綴和思想來解決
實際上a ^ b == 0 <--> a == b
,所以只要枚舉左右端點 i k 即可。如果當前區間 的異或和是 0,那麼 j 有 k - i 種取值
時間複雜度是,空間複雜度是
C++代碼
class Solution {
public:
int countTriplets(vector<int>& arr) {
// a ^ b == 0 <--> a == b
int n = arr.size(), res = 0;
for (int i = 0; i < n; i ++) {
int tmp = arr[i];
for (int k = i + 1; k < n; k ++) {
tmp ^= arr[k];
if (tmp == 0) res += (k - i);
}
}
return res;
}
};
附:超時代碼
class Solution {
public:
// 暴力超時
int solve (int m, int n, vector<int> &arr) {
int res = 0;
for (int i = m; i <= n; i ++) {
res ^= arr[i];
}
return res;
}
int countTriplets(vector<int> &arr) {
int n = arr.size(), cnt = 0;
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j; k < n; k++) {
if (solve(i, j - 1, arr) == solve(j, k, arr)) cnt ++;
}
}
}
return cnt;
}
};