3215. Count Triplets with Even XOR Set Bits II 🔒
Problem Description
You are given three integer arrays a
, b
, and c
. Your task is to count how many triplets (a[i], b[j], c[k])
exist such that when you perform bitwise XOR operation on all three elements (a[i] XOR b[j] XOR c[k]
), the result has an even number of set bits (1s in binary representation).
For example, if the XOR result is 10110
in binary, it has 3 set bits (three 1s), which is odd, so this triplet wouldn't be counted. But if the XOR result is 1001
in binary, it has 2 set bits (two 1s), which is even, so this triplet would be counted.
The key insight is that when XORing numbers, the parity (odd/even property) of set bits in the final result depends on the sum of parities of set bits in the individual numbers. If the sum of the number of set bits across the three numbers has a specific parity pattern, the XOR result will have an even number of set bits.
The solution leverages this property by:
- Counting the parity of set bits for each number in arrays
a
,b
, andc
- Using the fact that for XOR of three numbers to have even set bits, the sum of their individual set bit parities must follow a specific pattern
- Multiplying the counts of matching parity combinations to get the total number of valid triplets
Intuition
The key observation is that counting set bits in XOR results directly for all possible triplets would be inefficient. Instead, we need to find a pattern.
When we XOR three numbers, the parity (odd/even) of set bits in the result follows a mathematical rule. Let's think about how XOR works: for each bit position, XOR counts how many 1s appear across all numbers - if it's odd, the result bit is 1; if even, it's 0.
For three numbers x
, y
, and z
, if they have p
, q
, and r
set bits respectively, the parity of set bits in x XOR y XOR z
depends on (p + q + r) mod 2
. More specifically, when we XOR three numbers bit by bit, the final count of 1s has a predictable parity based on the individual parities.
Here's the crucial insight: instead of computing the actual XOR and counting bits for each triplet, we can just track whether each number has an odd or even number of set bits (parity = 0 for even, 1 for odd).
For the XOR result to have an even number of set bits, we need the sum of parities (i + j + k)
to satisfy a specific condition. Through XOR properties, we can determine that when (i + j + k) & 1 ^ 1
is true (which means the sum is even), the XOR result will have an even number of set bits.
This transforms our problem from O(n³) brute force checking into a counting problem: we count how many numbers in each array have even/odd parity of set bits, then multiply the counts for valid parity combinations. This gives us all valid triplets without actually computing each XOR operation.
Solution Approach
The solution uses bit manipulation and counting to efficiently solve the problem.
First, we create three counters cnt1
, cnt2
, and cnt3
to track the parity of set bits for each number in arrays a
, b
, and c
respectively. For each number x
in an array, we compute x.bit_count() & 1
:
x.bit_count()
returns the number of 1s in the binary representation ofx
& 1
gives us the parity (0 if even number of 1s, 1 if odd number of 1s)
The Counter
stores how many numbers in each array have even parity (0) and how many have odd parity (1).
Next, we enumerate all possible parity combinations using three nested loops, where i
, j
, and k
each range from 0 to 1:
i
represents the parity for numbers from arraya
j
represents the parity for numbers from arrayb
k
represents the parity for numbers from arrayc
For each combination (i, j, k)
, we check if (i + j + k) & 1 ^ 1
is true:
(i + j + k)
gives the sum of parities& 1
gets the least significant bit (parity of the sum)^ 1
flips the bit (equivalent to checking if the sum is even)
When this condition is true, it means the XOR of any triplet with these parities will have an even number of set bits. We then multiply cnt1[i] * cnt2[j] * cnt3[k]
to get the number of valid triplets for this parity combination and add it to our answer.
The multiplication works because each element with parity i
from array a
can be paired with each element with parity j
from array b
and each element with parity k
from array c
, giving us all possible triplets with the desired property.
Finally, we return the total count accumulated across all valid parity combinations.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Given:
a = [3, 5]
b = [2, 6]
c = [1, 4]
Step 1: Calculate parity of set bits for each number
For array a
:
3
in binary is11
→ 2 set bits → parity = 0 (even)5
in binary is101
→ 2 set bits → parity = 0 (even)cnt1 = {0: 2, 1: 0}
(both numbers have even parity)
For array b
:
2
in binary is10
→ 1 set bit → parity = 1 (odd)6
in binary is110
→ 2 set bits → parity = 0 (even)cnt2 = {0: 1, 1: 1}
(one even, one odd)
For array c
:
1
in binary is1
→ 1 set bit → parity = 1 (odd)4
in binary is100
→ 1 set bit → parity = 1 (odd)cnt3 = {0: 0, 1: 2}
(both numbers have odd parity)
Step 2: Check all parity combinations
We iterate through all combinations of (i, j, k)
where each can be 0 or 1:
-
(0, 0, 0)
: Sum = 0,(0 & 1) ^ 1 = 1
✓ Valid- Count =
cnt1[0] * cnt2[0] * cnt3[0] = 2 * 1 * 0 = 0
- Count =
-
(0, 0, 1)
: Sum = 1,(1 & 1) ^ 1 = 0
✗ Invalid -
(0, 1, 0)
: Sum = 1,(1 & 1) ^ 1 = 0
✗ Invalid -
(0, 1, 1)
: Sum = 2,(2 & 1) ^ 1 = 1
✓ Valid- Count =
cnt1[0] * cnt2[1] * cnt3[1] = 2 * 1 * 2 = 4
- Count =
-
(1, 0, 0)
: Sum = 1,(1 & 1) ^ 1 = 0
✗ Invalid -
(1, 0, 1)
: Sum = 2,(2 & 1) ^ 1 = 1
✓ Valid- Count =
cnt1[1] * cnt2[0] * cnt3[1] = 0 * 1 * 2 = 0
- Count =
-
(1, 1, 0)
: Sum = 2,(2 & 1) ^ 1 = 1
✓ Valid- Count =
cnt1[1] * cnt2[1] * cnt3[0] = 0 * 1 * 0 = 0
- Count =
-
(1, 1, 1)
: Sum = 3,(3 & 1) ^ 1 = 0
✗ Invalid
Step 3: Sum up valid combinations
Total = 0 + 4 + 0 + 0 = 4
Verification: The 4 valid triplets are:
(3, 2, 1)
:3 XOR 2 XOR 1 = 0
→ 0 set bits (even) ✓(3, 2, 4)
:3 XOR 2 XOR 4 = 5
→ 2 set bits (even) ✓(5, 2, 1)
:5 XOR 2 XOR 1 = 6
→ 2 set bits (even) ✓(5, 2, 4)
:5 XOR 2 XOR 4 = 3
→ 2 set bits (even) ✓
All other triplets like (3, 6, 1)
would give 3 XOR 6 XOR 1 = 4
→ 1 set bit (odd), which wouldn't be counted.
Solution Implementation
1from typing import List
2from collections import Counter
3
4class Solution:
5 def tripletCount(self, a: List[int], b: List[int], c: List[int]) -> int:
6 # Count the parity (even=0, odd=1) of bit counts for each array
7 # bit_count() returns the number of 1s in binary representation
8 # & 1 gives us the parity (0 for even, 1 for odd)
9 parity_count_a = Counter(x.bit_count() & 1 for x in a)
10 parity_count_b = Counter(x.bit_count() & 1 for x in b)
11 parity_count_c = Counter(x.bit_count() & 1 for x in c)
12
13 result = 0
14
15 # Iterate through all possible parity combinations
16 for parity_a in range(2): # 0 (even) or 1 (odd)
17 for parity_b in range(2): # 0 (even) or 1 (odd)
18 for parity_c in range(2): # 0 (even) or 1 (odd)
19 # Check if the sum of parities is even
20 # (i + j + k) & 1 gives 0 if sum is even, 1 if odd
21 # ^ 1 flips the bit, so we count when sum is even
22 if ((parity_a + parity_b + parity_c) & 1) == 0:
23 # Multiply the counts of elements with these parities
24 result += (parity_count_a[parity_a] *
25 parity_count_b[parity_b] *
26 parity_count_c[parity_c])
27
28 return result
29
1class Solution {
2 /**
3 * Counts the number of valid triplets (i, j, k) where elements from arrays a, b, and c
4 * form a triplet with an even sum of their bit counts.
5 *
6 * @param a First array
7 * @param b Second array
8 * @param c Third array
9 * @return Number of valid triplets
10 */
11 public long tripletCount(int[] a, int[] b, int[] c) {
12 // Count elements by bit count parity (even=0, odd=1) for each array
13 int[] parityCountA = new int[2]; // [evenBitCount, oddBitCount]
14 int[] parityCountB = new int[2];
15 int[] parityCountC = new int[2];
16
17 // Count elements in array 'a' by bit count parity
18 for (int element : a) {
19 int bitCount = Integer.bitCount(element);
20 int parity = bitCount & 1; // 0 if even bit count, 1 if odd
21 parityCountA[parity]++;
22 }
23
24 // Count elements in array 'b' by bit count parity
25 for (int element : b) {
26 int bitCount = Integer.bitCount(element);
27 int parity = bitCount & 1;
28 parityCountB[parity]++;
29 }
30
31 // Count elements in array 'c' by bit count parity
32 for (int element : c) {
33 int bitCount = Integer.bitCount(element);
34 int parity = bitCount & 1;
35 parityCountC[parity]++;
36 }
37
38 long totalValidTriplets = 0;
39
40 // Check all combinations of parities from the three arrays
41 for (int parityA = 0; parityA < 2; parityA++) {
42 for (int parityB = 0; parityB < 2; parityB++) {
43 for (int parityC = 0; parityC < 2; parityC++) {
44 // Sum of parities must be even for valid triplet
45 // (even + even + even = even, odd + odd + even = even)
46 if ((parityA + parityB + parityC) % 2 == 0) {
47 // Multiply counts to get number of valid triplets for this parity combination
48 totalValidTriplets += (long) parityCountA[parityA] *
49 parityCountB[parityB] *
50 parityCountC[parityC];
51 }
52 }
53 }
54 }
55
56 return totalValidTriplets;
57 }
58}
59
1class Solution {
2public:
3 long long tripletCount(vector<int>& a, vector<int>& b, vector<int>& c) {
4 // Count arrays to store the number of elements with even/odd number of set bits
5 // Index 0: count of numbers with even popcount, Index 1: count of numbers with odd popcount
6 int countA[2] = {0, 0};
7 int countB[2] = {0, 0};
8 int countC[2] = {0, 0};
9
10 // Count elements in array 'a' based on parity of their bit count
11 for (int num : a) {
12 int bitCount = __builtin_popcount(num); // Count number of 1s in binary representation
13 int parity = bitCount & 1; // 0 if even, 1 if odd
14 ++countA[parity];
15 }
16
17 // Count elements in array 'b' based on parity of their bit count
18 for (int num : b) {
19 int bitCount = __builtin_popcount(num);
20 int parity = bitCount & 1;
21 ++countB[parity];
22 }
23
24 // Count elements in array 'c' based on parity of their bit count
25 for (int num : c) {
26 int bitCount = __builtin_popcount(num);
27 int parity = bitCount & 1;
28 ++countC[parity];
29 }
30
31 long long result = 0;
32
33 // Iterate through all possible combinations of parities
34 for (int parityA = 0; parityA < 2; ++parityA) {
35 for (int parityB = 0; parityB < 2; ++parityB) {
36 for (int parityC = 0; parityC < 2; ++parityC) {
37 // Check if the sum of parities is even
38 // This means XOR of three numbers will have even popcount
39 if ((parityA + parityB + parityC) % 2 == 0) {
40 // Add the product of counts for this valid combination
41 result += 1LL * countA[parityA] * countB[parityB] * countC[parityC];
42 }
43 }
44 }
45 }
46
47 return result;
48 }
49};
50
1/**
2 * Counts the number of valid triplets (i, j, k) where the XOR of
3 * a[i], b[j], and c[k] has an even number of set bits.
4 *
5 * @param a - First array of numbers
6 * @param b - Second array of numbers
7 * @param c - Third array of numbers
8 * @returns The count of valid triplets
9 */
10function tripletCount(a: number[], b: number[], c: number[]): number {
11 // Count arrays to store the count of numbers with even/odd bit counts
12 // Index 0: count of numbers with even number of set bits
13 // Index 1: count of numbers with odd number of set bits
14 const countArrayA: [number, number] = [0, 0];
15 const countArrayB: [number, number] = [0, 0];
16 const countArrayC: [number, number] = [0, 0];
17
18 // Count the parity of set bits for each element in array a
19 for (const element of a) {
20 const parity = bitCount(element) & 1; // 0 for even, 1 for odd
21 ++countArrayA[parity];
22 }
23
24 // Count the parity of set bits for each element in array b
25 for (const element of b) {
26 const parity = bitCount(element) & 1;
27 ++countArrayB[parity];
28 }
29
30 // Count the parity of set bits for each element in array c
31 for (const element of c) {
32 const parity = bitCount(element) & 1;
33 ++countArrayC[parity];
34 }
35
36 let totalCount = 0;
37
38 // Check all combinations of parities
39 // XOR of three numbers has even bit count when the sum of their bit count parities is even
40 for (let parityA = 0; parityA < 2; ++parityA) {
41 for (let parityB = 0; parityB < 2; ++parityB) {
42 for (let parityC = 0; parityC < 2; ++parityC) {
43 // If sum of parities is even, XOR will have even number of set bits
44 if ((parityA + parityB + parityC) % 2 === 0) {
45 totalCount += countArrayA[parityA] * countArrayB[parityB] * countArrayC[parityC];
46 }
47 }
48 }
49 }
50
51 return totalCount;
52}
53
54/**
55 * Counts the number of set bits (1s) in the binary representation of a number.
56 * Uses Brian Kernighan's algorithm with bit manipulation optimizations.
57 *
58 * @param i - The input number
59 * @returns The count of set bits
60 */
61function bitCount(i: number): number {
62 // Step 1: Count bits in groups of 2
63 i = i - ((i >>> 1) & 0x55555555);
64
65 // Step 2: Count bits in groups of 4
66 i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
67
68 // Step 3: Count bits in groups of 8
69 i = (i + (i >>> 4)) & 0x0f0f0f0f;
70
71 // Step 4: Count bits in groups of 16
72 i = i + (i >>> 8);
73
74 // Step 5: Count bits in groups of 32
75 i = i + (i >>> 16);
76
77 // Mask to get only the lowest 6 bits (max count is 32 for 32-bit integer)
78 return i & 0x3f;
79}
80
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of arrays a
, b
, and c
. This is because:
- Creating
cnt1
requires iterating through arraya
to computex.bit_count() & 1
for each element, which takesO(n)
time - Creating
cnt2
requires iterating through arrayb
, which takesO(n)
time - Creating
cnt3
requires iterating through arrayc
, which takesO(n)
time - The triple nested loop iterates only through values 0 and 1 (2 iterations each), resulting in a constant
2 × 2 × 2 = 8
iterations - Each iteration performs constant time operations (multiplication and addition)
- Total:
O(n) + O(n) + O(n) + O(1) = O(n)
The space complexity is O(1)
. This is because:
- Each Counter (
cnt1
,cnt2
,cnt3
) stores at most 2 key-value pairs (keys can only be 0 or 1, sincex.bit_count() & 1
returns either 0 or 1) - The space used by the Counters is therefore constant, independent of input size
- The loop variables
i
,j
,k
andans
use constant space - Total:
O(1)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding the XOR Parity Property
A common mistake is thinking that XOR of three numbers with even bit counts always results in an even bit count. This is incorrect. The parity of the XOR result depends on a more complex relationship.
Incorrect assumption:
# WRONG: Checking if all three numbers have even bit counts if a[i].bit_count() % 2 == 0 and b[j].bit_count() % 2 == 0 and c[k].bit_count() % 2 == 0: count += 1
Correct approach: The XOR of three numbers has an even bit count when the sum of their individual bit count parities is even. This is because XOR operations preserve certain parity properties through the principle of linear algebra over GF(2).
2. Using Inefficient Brute Force
Another pitfall is implementing a naive O(n³) solution that checks every possible triplet:
Inefficient approach:
def tripletCount(self, a: List[int], b: List[int], c: List[int]) -> int:
count = 0
for i in range(len(a)):
for j in range(len(b)):
for k in range(len(c)):
xor_result = a[i] ^ b[j] ^ c[k]
if xor_result.bit_count() % 2 == 0:
count += 1
return count
This approach has O(n³) time complexity and will timeout for large inputs.
Solution: Use the counting approach shown in the original solution which reduces complexity to O(n) where n is the total length of all arrays, by leveraging the mathematical property that we only need to count parities.
3. Incorrect Parity Condition Check
Some might incorrectly implement the condition for checking valid parity combinations:
Wrong implementation:
# WRONG: Using XOR instead of checking sum parity if (parity_a ^ parity_b ^ parity_c) == 0: result += ...
Correct implementation:
# RIGHT: Check if sum of parities is even if ((parity_a + parity_b + parity_c) & 1) == 0: result += ...
The condition should check if the sum of parities is even, not their XOR. The sum being even ensures the final XOR result has an even number of set bits.
4. Missing Edge Cases
Not handling arrays with all zeros or single elements properly:
Robust solution includes:
- Arrays can contain zeros (which have 0 set bits, even parity)
- Arrays can have duplicate values (counted separately in triplets)
- Empty result when any array is empty (implicitly handled by Counter returning 0 for missing keys)
Which data structure is used to implement priority queue?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!