一、题目
给你一个整数数组 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)暴力法+记忆化
根据题目中对a和b的定义,可以使用最简单的三层for循环来确定i、j、k的值,根据定义求出a和b。
想要快速得出a和b的值,可以使用前缀异或值的记忆化,使用数组memo,memo[i]=arr[0] ^ arr[1] ^ … ^ arr[i - 1].
a = memo[i-1] ^ memo[j-1] b = memo[j-1] ^ memo[k]
2)两层循环方法
进一步理解题意,如果a==b,那么arr[i] ^ arr[i + 1] ^ … ^ arr[j - 1]^arr[j] ^ arr[j + 1] ^ … ^ arr[k]=0,也就是说,从i到k的所有元素异或值为0,那么只需要每当异或值为0时,就认定已经找到该三元组即可,无论j在(i, k]中哪个位置,都是满足题意的三元组,就找到了k-i个三元组。
三、代码
1)暴力法+记忆化
class Solution {public int countTriplets(int[] arr) {int[] memo = new int[arr.length + 1];for (int i = 1; i < memo.length; i++) {memo[i] = memo[i-1] ^ arr[i-1];}int ans = 0;for (int i = 1; i < memo.length - 1; i++) {for (int j = i + 1; j < memo.length; j++) {for (int k = j; k < memo.length; k++) {int a = memo[i-1] ^ memo[j-1];int b = memo[j-1] ^ memo[k];if (a == b) {ans++;}}}}return ans;}}
2)两层循环方法
class Solution {public int countTriplets(int[] arr) {int ans = 0;for (int i = 0; i < arr.length - 1; i++) {int temp = arr[i];for (int k = i+1; k < arr.length; k++) {temp ^= arr[k];if (temp == 0) {ans += k - i;}}}return ans;}}
时间复杂度为O(n),空间复杂度为O(1)。
