1442. Count Triplets That Can Form Two Arrays of Equal XOR - Explanation
Description
Count the index triples (i, j, k) satisfying 0 <= i < j <= k < arr.length for which the XOR of arr[i] through arr[j - 1] equals the XOR of arr[j] through arr[k]. Both ranges are nonempty. Return the number of such triples.
Example 1:
Input: arr = [4,4]
Output: 1Explanation: The only eligible triple is (0, 1, 1). Its two ranges are [4] and [4], which have equal XOR.
Example 2:
Input: arr = [1,2,4]
Output: 0Explanation: The eligible pairs of adjacent nonempty ranges have XORs (1,2), (1,6), (3,4), or (2,4). None are equal.
Example 3:
Input: arr = [3,3,3]
Output: 2Explanation: The triples (0, 1, 1) and (1, 2, 2) each compare two single entries equal to 3. The other eligible triples do not have equal XOR.
Constraints:
1 <= arr.length <= 3001 <= arr[i] <= 100000000
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Bitwise XOR - Understanding XOR properties like a XOR a = 0 and a XOR 0 = a
- Prefix Sums/XOR - Using cumulative operations to compute subarray results efficiently
- Hash Maps - Tracking counts and index sums for O(1) lookups in the optimal solution
1. Brute Force
Intuition
We need to find triplets (i, j, k) where a = arr[i] XOR arr[i+1] XOR ... XOR arr[j-1] equals b = arr[j] XOR arr[j+1] XOR ... XOR arr[k]. The most direct approach is to try all valid combinations of i, j, and k, compute both XOR values for each triplet, and count when they match.
Algorithm
- Initialize a result counter
resto0. - Iterate through all possible values of
ifrom0toN-2. - For each
i, iterate through all possible values ofjfromi+1toN-1. - For each
j, iterate through all possible values ofkfromjtoN-1. - Compute
aby XORing elements from indexitoj-1. - Compute
bby XORing elements from indexjtok. - If
a == b, incrementres. - Return
res.
class Solution:
def countTriplets(self, arr: List[int]) -> int:
N = len(arr)
res = 0
for i in range(N - 1):
for j in range(i + 1, N):
for k in range(j, N):
a = b = 0
for idx in range(i, j):
a ^= arr[idx]
for idx in range(j, k + 1):
b ^= arr[idx]
if a == b:
res += 1
return resTime & Space Complexity
- Time complexity:
- Space complexity: extra space.
2. Brute Force (Optimized)
Intuition
Instead of recomputing the XOR values from scratch for each triplet, we can build them incrementally. As we move j forward, we can extend a by XORing the next element. Similarly, as we move k forward, we can extend b by XORing the next element. This eliminates the innermost loops for computing XOR values.
Algorithm
- Initialize a result counter
resto0. - Iterate through all possible values of
ifrom0toN-2. - Initialize
ato0. - For each
jfromi+1toN-1:- Update
aby XORing it witharr[j-1]. - Initialize
bto0. - For each
kfromjtoN-1:- Update
bby XORing it witharr[k]. - If
a == b, incrementres.
- Update
- Update
- Return
res.
Time & Space Complexity
- Time complexity:
- Space complexity: extra space.
3. Math + Bitwise XOR
Intuition
The key insight is that if a == b, then a XOR b == 0, which means arr[i] XOR arr[i+1] XOR ... XOR arr[k] == 0. So we need to find subarrays where the XOR of all elements is 0. For any such subarray from index i to k, we can place j at any position from i+1 to k, giving us k - i valid triplets. This reduces the problem to finding pairs (i, k) where the subarray XOR is 0.
Algorithm
- Initialize a result counter
resto0. - Iterate through all possible starting indices
ifrom0toN-2. - Initialize
cur_xortoarr[i]. - For each ending index
kfromi+1toN-1:- Update
cur_xorby XORing it witharr[k]. - If
cur_xor == 0, addk - itores(representing all valid positions forj).
- Update
- Return
res.
Time & Space Complexity
- Time complexity:
- Space complexity: extra space.
4. Math + Bitwise XOR (Optimal)
Intuition
We can use prefix XOR to find subarrays with XOR equal to 0 in linear time. If prefix[i] == prefix[k+1], then the XOR from index i to k is 0. For each prefix value, we track how many times we have seen it and the sum of indices where it occurred. When we see the same prefix again at index k, the contribution to the result is k * count - sum_of_indices, where count is how many times this prefix appeared before, and the formula accounts for all k - i values.
Algorithm
- Initialize
resandprefixto0. - Create two hash maps:
countto store frequency of each prefix value, andindex_sumto store sum of indices for each prefix value. - Initialize
count[0] = 1to handle subarrays starting from index0. - For each index
ifrom0toN-1:- Update
prefixby XORing it witharr[i]. - If this prefix value has been seen before, add
i * count[prefix] - index_sum[prefix]tores. - Increment
count[prefix]by1. - Add
i + 1toindex_sum[prefix].
- Update
- Return
res.
class Solution:
def countTriplets(self, arr: List[int]) -> int:
N = len(arr)
res = prefix = 0
count = defaultdict(int) # number of prefixes
index_sum = defaultdict(int) # sum of indices with that prefix
count[0] = 1
for i in range(N):
prefix ^= arr[i]
if prefix in count:
res += i * count[prefix] - index_sum[prefix]
count[prefix] += 1
index_sum[prefix] += i + 1
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Misunderstanding the Triplet Count Formula
When the XOR from index i to k equals zero, beginners often count it as just 1 triplet. However, j can be placed at any position from i+1 to k, yielding k - i valid triplets for each such pair.
# Incorrect - counts only one triplet per zero-XOR subarray
if cur_xor == 0:
res += 1
# Correct - counts all valid j positions
if cur_xor == 0:
res += k - iOff-by-One Errors in Index Sum Tracking
In the optimal solution, the index sum needs to track i + 1 (not i) because we want the sum of starting positions for subarrays, and the formula i * count - index_sum requires this offset. Using just i leads to incorrect results.
# Incorrect - missing the +1 offset
index_sum[prefix] += i
# Correct - accounts for 1-based position in contribution formula
index_sum[prefix] += i + 1Forgetting to Initialize count[0] = 1
The prefix XOR of 0 needs to be pre-initialized to handle subarrays starting from index 0. Without this initialization, valid triplets where the XOR from index 0 to some k equals zero will be missed.
# Incorrect - misses subarrays starting from index 0
count = defaultdict(int)
# Correct - handles prefix XOR that equals a previously seen value at index 0
count = defaultdict(int)
count[0] = 1
Sign in to join the discussion