给你一个整数数组 arr
。
现需要从数组中取三个下标 i
、j
和 k
,其中 (0 <= i < j <= k < arr.length)
。
a
和 b
定义如下:
a = arr[i] ^ arr[i + 1] ^ ... ^ arr[j - 1]
b = arr[j] ^ arr[j + 1] ^ ... ^ arr[k]
注意:^ 表示 按位异或 操作。
请返回能够令 a == b
成立的三元组 (i
, j
, k
) 的数目。
示例 1:
输入:arr = [2,3,1,6,7] 输出:4 解释:满足题意的三元组分别是 (0,1,2), (0,2,2), (2,3,4) 以及 (2,4,4)
示例 2:
输入:arr = [1,1,1,1,1] 输出:10
示例 3:
输入:arr = [2,3] 输出:0
示例 4:
输入:arr = [1,3,5,7,9] 输出:3
示例 5:
输入:arr = [7,11,12,9,5,2,7,17,22] 输出:8
提示:
1 <= arr.length <= 300
1 <= arr[i] <= 10^8
提示 1
We are searching for sub-array of length ≥ 2 and we need to split it to 2 non-empty arrays so that the xor of the first array is equal to the xor of the second array. This is equivalent to searching for sub-array with xor = 0.
提示 2
Keep the prefix xor of arr in another array, check the xor of all sub-arrays in O(n^2), if the xor of sub-array of length x is 0 add x-1 to the answer.
解法1:前缀和 + 三重循环
用 ⊕ 表示按位异或运算。
定义长度为 n 的数组 arr 的异或前缀和
由该定义可得
这是一个关于 Si 的递推式,根据该递推式我们可以用 O(n) 的时间得到数组 arr 的异或前缀和数组。
对于两个下标不同的异或前缀和 Si 和 Sj ,设 0<i<j,有
由于异或运算满足结合律和交换律,且任意数异或自身等于 0,上式可化简为
从而,数组 arr 的子区间 [i,j] 的元素异或和为可表示为
因此问题中的 a 和 b 可表示为
若 a=b,则有
即
Java版:
class Solution {
public int countTriplets(int[] arr) {
int n = arr.length;
int prexor[] = new int[n + 1];
for (int i = 1; i <= n; i++) {
prexor[i] = prexor[i - 1] ^ arr[i - 1];
}
int ans = 0;
// 0 <= i < j <= k < n
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j; k < n; k++) {
if (prexor[i] == prexor[k + 1]) {
ans++;
}
}
}
}
return ans;
}
}
Python3版:
class Solution:
def countTriplets(self, arr: List[int]) -> int:
n = len(arr)
pre = [0] * (n + 1)
for i in range(1, n + 1):
pre[i] = pre[i - 1] ^ arr[i - 1]
ans = 0
for i in range(0, n - 1):
for j in range(i + 1, n):
for k in range(j, n):
if pre[i] == pre[k + 1]:
ans += 1
return ans
复杂度分析
-
时间复杂度:O(n^3),其中 n 是数组 arr 的长度。
-
空间复杂度:O(n)。
解法2:前缀和 + 二重循环
当等式 S i =S k+1 成立时,[i+1,k] 的范围内的任意 j 都是符合要求的,对应的三元组个数为 k−i。因此我们只需枚举下标 i 和 k。
Java版:
class Solution {
public int countTriplets(int[] arr) {
int n = arr.length;
int prexor[] = new int[n + 1];
for (int i = 1; i <= n; i++) {
prexor[i] = prexor[i - 1] ^ arr[i - 1];
}
int ans = 0;
// 0 <= i < j <= k < n
for (int i = 0; i < n - 1; i++) {
for (int k = i + 1; k < n; k++) {
if (prexor[i] == prexor[k + 1]) {
// i 和 k 位置固定,j有 k - i 种可能的位置
ans += k - i;
}
}
}
return ans;
}
}
Python3版:
class Solution:
def countTriplets(self, arr: List[int]) -> int:
n = len(arr)
pre = [0] * (n + 1)
for i in range(1, n + 1):
pre[i] = pre[i - 1] ^ arr[i - 1]
ans = 0
for i in range(0,n - 1):
for k in range(i + 1, n):
if pre[i] == pre[k + 1]:
ans += k - i
return ans
复杂度分析
-
时间复杂度:O(n^2),其中 n 是数组 arr 的长度。
-
空间复杂度:O(n)。
解法3:前缀和 + 哈希表
Java版:
class Solution {
public int countTriplets(int[] arr) {
int n = arr.length;
int[] prexor = new int[n + 1];
for (int i = 1; i <= n; i++) {
prexor[i] = prexor[i - 1] ^ arr[i - 1];
}
int ans = 0;
Map<Integer, Integer> counts = new HashMap<>();
Map<Integer, Integer> sum = new HashMap<>();
for (int k = 0; k < n; k++) {
if (counts.containsKey(prexor[k + 1])) {
ans += counts.get(prexor[k + 1]) * k - sum.get(prexor[k + 1]);
}
counts.merge(prexor[k], 1, Integer::sum);
sum.merge(prexor[k], k, Integer::sum);
}
return ans;
}
}
或
class Solution {
public int countTriplets(int[] arr) {
int n = arr.length;
int[] prexor = new int[n + 1];
for (int i = 1; i <= n; i++) {
prexor[i] = prexor[i - 1] ^ arr[i - 1];
}
int ans = 0;
Map<Integer, Integer> counts = new HashMap<>();
Map<Integer, Integer> sum = new HashMap<>();
counts.put(0, 1);
sum.put(0, 0);
for (int k = 1; k < n; k++) {
if (counts.containsKey(prexor[k + 1])) {
ans += counts.get(prexor[k + 1]) * k - sum.get(prexor[k + 1]);
}
counts.merge(prexor[k], 1, Integer::sum);
sum.merge(prexor[k], k, Integer::sum);
}
return ans;
}
}
Python3版:
class Solution:
def countTriplets(self, arr: List[int]) -> int:
n = len(arr)
pre = [0] * (n + 1)
for i in range(1, n + 1):
pre[i] = pre[i - 1] ^ arr[i - 1]
ans = 0
counts = {}
total = {}
for k in range(0, n):
if pre[k + 1] in counts:
ans += counts[pre[k + 1]] * k - total[pre[k + 1]]
counts[pre[k]] = 1 if pre[k] not in counts else counts[pre[k]] + 1
total[pre[k]] = k if pre[k] not in total else total[pre[k]] + k
return ans
复杂度分析
-
时间复杂度:O(n),其中 n 是数组 arr 的长度。
-
空间复杂度:O(n)。我们需要使用 O(n) 的空间存储两个哈希表。
优化
我们可以在计算异或前缀和的同时计算答案,从而做到仅遍历 arr 一次就计算出答案。
java版:
class Solution {
public int countTriplets(int[] arr) {
int ans = 0;
int pre = 0;
Map<Integer, Integer> counts = new HashMap<>();
Map<Integer, Integer> sum = new HashMap<>();
for (int k = 0; k < arr.length; k++) {
int pre1 = pre ^ arr[k];
if (counts.containsKey(pre1)) {
ans += counts.get(pre1) * k - sum.get(pre1);
}
counts.merge(pre, 1, Integer::sum);
sum.merge(pre, k, Integer::sum);
pre ^= arr[k];
}
return ans;
}
}
Python3版:
class Solution:
def countTriplets(self, arr: List[int]) -> int:
counts = {}
total = {}
ans = 0
pre = 0
for k in range(0, len(arr)):
val = pre ^ arr[k]
if val in counts:
ans += counts[val] * k - total[val]
counts[pre] = 1 if pre not in counts else counts[pre] + 1
total[pre] = k if pre not in total else total[pre] + k
pre ^= arr[k]
return ans
复杂度分析
-
时间复杂度:O(n),其中 n 是数组 arr 的长度。
-
空间复杂度:O(n)。我们需要使用 O(n) 的空间存储两个哈希表。