【LeetCode】1442. 形成两个异或相等数组的三元组数目

140 阅读3分钟

形成两个异或相等数组的三元组数目

给你一个整数数组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的位置,第二层循环计算ij-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
}