classSolution: defcountTriplets(self, arr: List[int]) -> int: n = len(arr) pre = [0] * (n + 1) # Prefix Sum for i, x inenumerate(arr): pre[i + 1] = pre[i] ^ x ans = 0 for i inrange(n): # i < j <= k for j inrange(i + 1, n): for k inrange(j, n): # if pre[i] ^ pre[j] == pre[j] ^ pre[k + 1]: if pre[i] == pre[k + 1]: # pre[j] is not important ans += 1 return ans
classSolution { public: int n; vector<int> pre; intcountTriplets(vector<int>& arr){ n = arr.size(); pre = vector<int>(n + 1); for (int i = 0; i < n; i++) pre[i + 1] = pre[i] ^ arr[i]; returnsolve1(arr); } intsolve1(vector<int>& arr){ int ans = 0; for (int i = 0; i < n; i++) // i < j <= k for (int j = i+1; j < n; j++) for (int k = j; k < n; k++) // if ((pre[i] ^ pre[j]) == (pre[j] ^ pre[k+1])) ans++; if (pre[i] == pre[k+1]) ans++; return ans; } };
classSolution: defcountTriplets(self, arr: List[int]) -> int: n = len(arr) pre = [0] * (n + 1) # Prefix Sum for i, x inenumerate(arr): pre[i + 1] = pre[i] ^ x ans = 0 for i inrange(n): # i < j <= k for k inrange(i + 1, n): if pre[i] == pre[k + 1]: # j is not important ans += k - i # (i, i+1, k), (i, i+2, k), ..., (i, k, k) return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution { public: int n; vector<int> pre; intcountTriplets(vector<int>& arr){ n = arr.size(); pre = vector<int>(n + 1); for (int i = 0; i < n; i++) pre[i + 1] = pre[i] ^ arr[i]; returnsolve2(arr); } intsolve2(vector<int>& arr){ int ans = 0; for (int i = 0; i < n; i++) // i < j <= k for (int k = i+1; k < n; k++) if (pre[i] == pre[k+1]) ans += k - i; // (i, i+1, k), (i, i+2, k), ..., (i, k, k) return ans; } };
方法三:雜湊表(Hash Table)
由於能夠滿足條件的 (i,j,k) 皆滿足 pre[i]==pre[k+1] ,對於每個 k ,我們只在乎能夠使得 pre[i]==pre[k+1] 的 i 有哪些,因此我們可以建立一個雜湊表 pos ,保存每個 pre[i] 出現的位置。
接著使用一重迴圈枚舉 k,對於每個 k,檢查 pre[k+1] 是否在 pos 中,若在則 pos[pre[k+1]] 中的每個 i ,其對答案的貢獻為 k−i ,累加到答案中,這部分和方法二中的思路相同。最後再把當前的 k 加入 pos[pre[k]] 中,以便後續的計算。
複雜度分析
時間複雜度 O(n2)
空間複雜度 O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defcountTriplets(self, arr: List[int]) -> int: n = len(arr) pre = [0] * (n + 1) # Prefix Sum for i, x inenumerate(arr): pre[i + 1] = pre[i] ^ x pos = defaultdict(list) ans = 0 for k inrange(n): if pre[k + 1] in pos: for i in pos[pre[k + 1]]: ans += k - i pos[pre[k]].append(k) return ans
classSolution { public: int n; vector<int> pre; intcountTriplets(vector<int>& arr){ n = arr.size(); pre = vector<int>(n + 1); for (int i = 0; i < n; i++) pre[i + 1] = pre[i] ^ arr[i]; returnsolve3a(arr); } intsolve3a(vector<int>& arr){ int ans = 0; unordered_map<int, vector<int>> pos; for (int k = 0; k < n; k++) { if (pos.count(pre[k+1])) { for (int i : pos[pre[k+1]]) { ans += k - i; } } pos[pre[k]].push_back(k); } return ans; } };
方法三優化:雜湊表(Hash Table) + 一重迴圈
方法三中,雖然已經節省了枚舉 i,j 的時間,但是在枚舉 k 的時候,仍然需要遍歷 pos[pre[k+1]] 中的每個 i,在最壞情況下,時間複雜度仍然是 O(n2) 。
因此,可以將 pos[pre[k+1]] 的長度和下標的總和都保存下來,這樣在枚舉 k 的時候,只需要計算 k×m 和 ∑i∈pos[pre[k+1]]i 即可。
這裡使用兩個 雜湊表(Hash Table) cnt 和 tot 來保存 pos[pre[k+1]] 的長度以及總和,這樣就可以在一重迴圈中完成計算。
複雜度分析
時間複雜度 O(n)
空間複雜度 O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defcountTriplets(self, arr: List[int]) -> int: n = len(arr) pre = [0] * (n + 1) # Prefix Sum for i, x inenumerate(arr): pre[i + 1] = pre[i] ^ x cnt = Counter() tot = Counter() ans = 0 for k inrange(n): if pre[k + 1] in cnt: ans += cnt[pre[k + 1]] * k - tot[pre[k + 1]] cnt[pre[k]] += 1 tot[pre[k]] += k return ans