Given an array of N distinct integers, count the number of unique triplets (a[i], a[j], a[k]) whose XOR is 0. A triplet is considered unique when it contains three different elements.
- The naive approach checks every possible triplet using three nested loops.
- The efficient approach uses a hash set to find the third element in constant average time.
Examples
Input : a[] = {1, 3, 5, 10, 14, 15};
Output : 2
Explanation : {1, 14, 15} and {5, 10, 15} are the
unique triplets whose XOR is 0.
{1, 14, 15} and all other combinations of
1, 14, 15 are considered as 1 only.
Input : a[] = {4, 7, 5, 8, 3, 9};
Output : 1
Explanation : {4, 7, 3} is the only triplet whose XOR is 0
Naive Approach
The naive approach checks every possible combination of three elements using three nested loops. For each triplet, calculate its XOR and increment the count if the result is 0.
Steps
- Select the first element using a loop.
- Select the second element using a loop starting from i + 1.
- Select the third element using a loop starting from j + 1.
- Check whether a[i] ^ a[j] ^ a[k] is 0.
- Increment the count if the condition is satisfied.
Efficient Approach
The XOR operation has the property:
x ^ x = 0
For a triplet whose XOR is 0:
a[i] ^ a[j] ^ a[k] = 0
This means:
a[k] = a[i] ^ a[j]
Therefore, for every pair of elements, we can calculate their XOR and check whether the result exists in the array. An unordered_set allows this lookup in O(1) average time.
Steps
- Store all array elements in an unordered_set.
- Generate every pair (a[i], a[j]) where i < j.
- Calculate xr = a[i] ^ a[j].
- Check whether xr exists in the set and is different from both a[i] and a[j].
- Increment the count if the condition is satisfied.
- Return count / 3 because each valid triplet is counted three times, once for each pair of its elements.
Example: Program to count the number of unique triplets whose XOR is 0
#include <bits/stdc++.h>
using namespace std;
// function to count the number of
// unique triplets whose xor is 0
int countTriplets(int a[], int n)
{
// To store values that are present
unordered_set<int> s;
for (int i = 0; i < n; i++)
s.insert(a[i]);
// stores the count of unique triplets
int count = 0;
// traverse for all i, j pairs such that j>i
for (int i = 0; i < n-1; i++) {
for (int j = i + 1; j < n; j++) {
// xor of a[i] and a[j]
int xr = a[i] ^ a[j];
// if xr of two numbers is present,
// then increase the count
if (s.find(xr) != s.end() && xr != a[i] &&
xr != a[j])
count++;
}
}
// returns answer
return count / 3;
}
// Driver code to test above function
int main()
{
int a[] = {1, 3, 5, 10, 14, 15};
int n = sizeof(a) / sizeof(a[0]);
cout << countTriplets(a, n);
return 0;
}
Output:Ā
2Explanation
- unordered_set stores all elements for fast lookup.
- The nested loops generate every unique pair of elements.
- a[i] ^ a[j] gives the value required to make the triplet XOR equal to 0.
- The set checks whether this required value exists in the array.
- count / 3 removes duplicate counting because each valid triplet is found through each of its three pairs.