[LeetCode解题报告] 1442. 形成两个异或相等数组的三元组数目
一、 题目
1. 题目描述
给你一个整数数组 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
Related Topics
- 位运算
- 数组
- 哈希表
- 数学
- 前缀和
- 👍 206
- 👎 0
2. 原题链接
二、 解题报告
1. 思路分析
抄袭官方题解。
题意实际是找两个相邻区间,使得这俩区间的异或和相同。
- 先求出前缀异或和S.
- 可证明:
- 区间[i,j]的异或和为S[i,j]=S[i]^S[j+1]
- 若S[i,j) ==S[j,k] 即 S[i]^S[j] == S[j]^S[k+1]
- 上式可以转化为S[i]==S[k+1],此时j取(i,k]中的任意数都符合。
- 那么问题转化为:求满足条件的三元组i,j,k,有多少个
那么我们枚举,i,j,当S[i]==S[k+1],j有多少个就计数上即可。这样是O(n2)。 - 继续优化:
- 对于每个k,若前边有m个i满足S[i]==S[k+1],这m个组合的和为:
(k-i1)+(k-i2)+…(k-im-1)+(k-im)
= m*k-(i1+i2+…im) - 即前边i的个数和i的和,用两个字典记。
2. 复杂度分析
最坏时间复杂度O(n)
3. 代码实现
前缀异或和
。
class Solution:
def countTriplets(self, arr: List[int]) -> int:
n = len(arr)
presum = list(accumulate(arr,initial=0,func=xor))
def sum_interval(i,j):
return presum[j+1]^presum[i]
cnt,total = defaultdict(int),defaultdict(int)
ans = 0
for k in range(0,n):
# presum[k+1] == presum[i] 则[i,k]中间j任意,都是满足需求的三元组
s = presum[k+1]
if s in cnt:
ans += cnt[s]*k - total[s]
cnt[presum[k]] += 1
total[presum[k]] += k
return ans
三、 本题小结
- 前缀异或和。