LeetCode 1442 - Count Triplets That Can Form Two Arrays of Equal XOR
The problem asks us to find the number of triplets (i, j, k) in an array arr such that the XOR of elements from index i
Difficulty: 🟡 Medium
Topics: Array, Hash Table, Math, Bit Manipulation, Prefix Sum
Solution
Problem Understanding
The problem asks us to find the number of triplets (i, j, k) in an array arr such that the XOR of elements from index i to j-1 equals the XOR of elements from index j to k. Formally, for 0 <= i < j <= k < arr.length, define:
a = arr[i] ^ arr[i+1] ^ ... ^ arr[j-1]
b = arr[j] ^ arr[j+1] ^ ... ^ arr[k]
We need to count all triplets where a == b.
The input is a 1-dimensional integer array with length up to 300, and each element is at most 10^8. The output is a single integer representing the number of valid triplets.
Key observations include:
- The XOR operation is associative and commutative, which allows us to use prefix XOR sums to compute ranges efficiently.
- Edge cases include arrays with identical elements, very short arrays, or arrays where no triplet exists.
- The constraints allow for an O(n^2) solution, but an O(n^3) brute-force approach may be too slow.
Approaches
Brute Force
The brute-force solution iterates over all possible triplets (i, j, k) and computes a and b directly by iterating over the subarrays. While correct, this approach has three nested loops, giving a time complexity of O(n^3). For n = 300, this could involve up to 27 million iterations, which is inefficient.
Optimal Approach
The key insight is using prefix XOR. Define prefixXOR[x] as the XOR of all elements from index 0 to x-1. Then, the XOR of any subarray arr[i:j] can be computed in O(1) as:
arr[i] ^ ... ^ arr[j] = prefixXOR[j+1] ^ prefixXOR[i]
We can rewrite the condition a == b as:
prefixXOR[j] ^ prefixXOR[i] == prefixXOR[k+1] ^ prefixXOR[j]
Simplifying gives:
prefixXOR[i] == prefixXOR[k+1]
This allows us to fix i and k and then compute the number of valid j values in between. Every pair (i, k) where prefixXOR[i] == prefixXOR[k+1] contributes (k - i) valid triplets. This reduces the time complexity to O(n^2).
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n^3) | O(1) | Check all triplets explicitly |
| Optimal | O(n^2) | O(n) | Use prefix XOR and count valid ranges |
Algorithm Walkthrough
- Initialize a
prefixXORarray of lengthn+1, withprefixXOR[0] = 0. - Compute
prefixXOR[i+1] = prefixXOR[i] ^ arr[i]for allifrom 0 to n-1. This stores XOR of all elements up to but not including index i+1. - Initialize a counter
count = 0. - Iterate over all
ifrom 0 to n-1. - For each
i, iterate over allkfromi+1to n-1. - If
prefixXOR[i] == prefixXOR[k+1], add(k - i)tocount. - Return
count.
Why it works: XOR has the property that x ^ x = 0 and x ^ 0 = x. By computing prefix XOR, we reduce the problem of comparing two subarrays to a simple equality check between prefixXOR[i] and prefixXOR[k+1]. The number of valid j indices between i and k is exactly (k - i).
Python Solution
from typing import List
class Solution:
def countTriplets(self, arr: List[int]) -> int:
n = len(arr)
prefixXOR = [0] * (n + 1)
for i in range(n):
prefixXOR[i + 1] = prefixXOR[i] ^ arr[i]
count = 0
for i in range(n):
for k in range(i + 1, n):
if prefixXOR[i] == prefixXOR[k + 1]:
count += (k - i)
return count
Explanation: We first compute prefixXOR to allow O(1) subarray XOR computation. Then we iterate over all possible pairs (i, k) and check if they satisfy the condition. Each valid pair contributes (k - i) triplets.
Go Solution
func countTriplets(arr []int) int {
n := len(arr)
prefixXOR := make([]int, n+1)
for i := 0; i < n; i++ {
prefixXOR[i+1] = prefixXOR[i] ^ arr[i]
}
count := 0
for i := 0; i < n; i++ {
for k := i + 1; k < n; k++ {
if prefixXOR[i] == prefixXOR[k+1] {
count += k - i
}
}
}
return count
}
Go-specific notes: The slice prefixXOR is preallocated with make and initialized to zeros automatically. Integer overflow is not a concern as Go uses 64-bit integers by default for XOR operations on slices of int.
Worked Examples
Example 1: arr = [2,3,1,6,7]
Compute prefixXOR: [0, 2, 1, 0, 6, 1].
Iterate (i, k) pairs:
| i | k | prefixXOR[i] | prefixXOR[k+1] | k-i | Add to count? |
|---|---|---|---|---|---|
| 0 | 1 | 0 | 1 | 1 | No |
| 0 | 2 | 0 | 0 | 2 | Yes, count+=2 |
| 0 | 3 | 0 | 6 | 3 | No |
| 0 | 4 | 0 | 1 | 4 | No |
| 1 | 2 | 2 | 0 | 1 | No |
| 1 | 3 | 2 | 6 | 2 | No |
| 1 | 4 | 2 | 1 | 3 | No |
| 2 | 3 | 1 | 6 | 1 | No |
| 2 | 4 | 1 | 1 | 2 | Yes, count+=2 |
| 3 | 4 | 0 | 1 | 1 | No |
Total count = 4.
Example 2: arr = [1,1,1,1,1]
Compute prefixXOR: [0,1,0,1,0,1].
Following the same logic, every pair (i,k) where prefixXOR[i] == prefixXOR[k+1] contributes k-i triplets. Total count = 10.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n^2) | Two nested loops over n elements, computing subarray XOR in O(1) using prefixXOR |
| Space | O(n) | Store prefixXOR array of size n+1 |
The complexity is efficient for n ≤ 300, as O(n^2) involves at most 90,000 iterations, which is acceptable.
Test Cases
# Example cases
assert Solution().countTriplets([2,3,1,6,7]) == 4 # given example 1
assert Solution().countTriplets([1,1,1,1,1]) == 10 # given example 2
# Edge cases
assert Solution().countTriplets([1]) == 0 # single element, no triplets
assert Solution().countTriplets([1,2]) == 0 # two elements, no triplets
assert Solution().countTriplets([1,2,3]) == 1 # minimal triplet
assert Solution().countTriplets([0,0,0,0]) == 6 # all zeros, multiple triplets
assert Solution().countTriplets([1,2,1,2,1]) == 4 # alternating pattern
| Test | Why |
|---|---|
| [2,3,1,6,7] | Validates general case with mix of numbers |
| [1,1,1,1,1] | All elements identical |
| [1] | Single element, no triplets possible |
| [1,2] | Array too short for a triplet |
| [1,2,3] | Minimal array forming exactly |