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

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

给你一个整数数组 arr 。

现需要从数组中取三个下标 ij 和 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 成立的三元组 (ij , 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) 的空间存储两个哈希表。

  • 32
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值