形成两个异或相等数组的三元组数目
给你一个整数数组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
思路
- 根据本题,首先想到的是暴力求解,因为涉及到是i,j和k三个来确定元素范围,因此需要三层for循环。第一层for循环确定i的位置,第二层循环计算i
j-1范围内的异或值,第三层循环计算jk范围内的异或值。 - 同时需要两个变量来存放上述两个范围内的异或值。如解法一。
- 在计算异或值的时候,常用到a^0=a,b^b=0,因此a^b^b=a.基于此,可以得到下面的公式:
arr[i]^arr[i+1]^,...,^arr[j]=
(arr[0]^arr[1]^,...,^arr[i-1])^
(arr[0]^arr[1]^,...,^arr[i-1])^
(arr[i]^arr[i+1]^,...,^arr[j])
- 基于上面的公式,我们可以想到“前缀和”,当然这里的“和”就是“异或值”。需要定义个数组dp,存放每个位置之前的前缀异或值,如dp[i]表示前i个元素的前缀异或值。在本题中a=dp[i]^dp[j],b=dp[j]^dp[k+1]。如解法二。
- 通过查看官方解析,将三层循环降低至两层循环。如下分析:
(arr[0]^arr[1]^,...,^arr[i-1])^(arr[i]^arr[i+1]^,...,^arr[j-1]^arr[j]^arr[j+1]^,...,^arr[k])
由于存在a==b,可以得出
(arr[i]^arr[i+1]^,...,^arr[j-1])^(arr[j]^arr[j+1]^,...,^arr[k]) =0
说明
arr[0]^arr[1]^,...,^arr[i-1]^(arr[i]^,...,^arr[j-1]^arr[j]^arr[j+1]^,...,^arr[k]) =
arr[0]^arr[1]^,...,^arr[i-1]
要使得上述公式为0,即dp[i]=dp[k+1],如解法三。
解法一
func countTriplets(arr []int) int {
count:=0
for i:=0;i<len(arr)-1;i++{ // 第一层for循环确定i的位置
a:=0 // 定义变量a存放i~j-1范围内的异或值,每次更新i,更新a
for j:=i+1;j<len(arr);j++{ // 第二层循环确定i~j-1范围内的异或值
a=a^arr[j-1]
b:=0 // 定义变量b存放j~k范围内的异或值,每次更新j,更b
for k:=j;k<len(arr);k++{ // 第三层循环计算j~k范围内的异或值
b=b^arr[k]
if a==b{
count++
}
}
}
}
return count
}
解法二
func countTriplets(arr []int) int {
dp:=make([]int,len(arr)+1)
for i:=0;i<len(arr);i++{ // 计算“前缀异或值”,其中dp[0]=0,dp[1]=arr[1]
dp[i+1]=dp[i]^arr[i]
}
count:=0
for i:=0;i<len(arr);i++{ // 第一层for循环确定i的位置
for j:=i+1;j<len(arr);j++{ // 第两层for循环确定j的位置
for k:=j;k<len(arr);k++{ // 第三层for循环确定k的位置
a:=dp[i]^dp[j] // i~j-1范围内的异或值
b:=dp[j]^dp[k+1] // j~k范围内的异或值
if a==b{
count=count+1
}
}
}
}
return count
}
解法三
func countTriplets(arr []int) int {
dp:=make([]int,len(arr)+1)
for i:=0;i<len(arr);i++{ // 计算“前缀异或值”,其中dp[0]=0,dp[1]=arr[1]
dp[i+1]=dp[i]^arr[i]
}
count:=0
for i:=0;i<len(arr);i++{
for k:=i+1;k<len(arr);k++{
if dp[i]==dp[k+1]{ // 0~i-1范围内的异或值和0~k范围内的异或值
count=count+(k-i)
}
}
}
return count
}