Facebook Pixel

3199. Count Triplets with Even XOR Set Bits I 🔒

EasyBit ManipulationArray
Leetcode Link

Problem Description

Given three integer arrays a, b, and c, you need to determine the number of triplets (a[i], b[j], c[k]) such that the bitwise XOR of these elements results in a number with an even number of set bits. A set bit is a 1 in the binary representation of the number. Your task is to return this count.

Intuition

To solve this problem, we begin by understanding how the bitwise XOR operates. The critical observation is that the parity (even or odd nature) of the count of set bits in the result of an XOR operation depends on the parity of the count of set bits in the individual numbers involved.

  1. Bit Count & Parity: For each number in the arrays a, b, and c, determine whether the number of set bits in its binary form is even or odd. This will help us to keep track of the parity of set bits using bit_count() & 1 which results in 0 for even and 1 for odd.

  2. Count Parity Types: Use counters to tally how many numbers in each array have an even number of set bits and how many have an odd number of set bits. This facilitates quick access when calculating the desired number of triplets.

  3. Constructing Triplets: Iterate over all combinations of parities from the three arrays (i.e., even or odd, represented by 0 or 1). For each combination, check if the sum of these parities results in an even number. If so, the total number of set bits in the XOR would be even as requested.

  4. Calculate Results: For valid combinations (where the sum of parities is even), multiply their counts from the respective arrays and sum these products to get the total number of qualifying triplets.

By systematically applying these insights, you can efficiently determine the number of triplets that satisfy the problem's criteria without directly computing the XOR for every possible triplet.

Solution Approach

To implement the solution, the approach leverages bit manipulation techniques along with counting data structures. Here's a detailed walkthrough of the algorithm and data structures used:

  1. Counting Parity with Counters:

    • Use the Counter from the collections module to track the parity of the number of set bits (0 for even, 1 for odd) in each number of the arrays a, b, and c.
    • Utilize the expression x.bit_count() & 1 to compute the parity of set bits for each element x.
    cnt1 = Counter(x.bit_count() & 1 for x in a)
    cnt2 = Counter(x.bit_count() & 1 for x in b)
    cnt3 = Counter(x.bit_count() & 1 for x in c)
  2. Iterate Over Parity Combinations:

    • There are only two states for parity (even and odd), represented by 0 and 1. Iterate over all possible combinations of parities for numbers from arrays a, b, and c.
    • Use nested loops to cover combinations: (i, j, k) where i, j, k can be either 0 or 1.
    for i in range(2):
        for j in range(2):
            for k in range(2):
  3. Conditional Check and Accumulation:

    • If the sum of i, j, and k is even (checking using (i + j + k) & 1 ^ 1), multiply the counts of the respective parity from each array and add to the answer accumulator ans.
    if (i + j + k) & 1 ^ 1:
        ans += cnt1[i] * cnt2[j] * cnt3[k]
  4. Return Result:

    • After tallying all valid combinations, return ans which contains the total number of qualifying triplets.
    return ans

This approach is efficient because it avoids the need for a triple nested loop over all elements of a, b, and c, instead iterating only over parity combinations and leveraging the mathematical properties of XOR and binary representations.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's consider a small example to illustrate the solution approach:

Suppose we have three arrays:

  • a = [3, 5]
  • b = [7, 1]
  • c = [6, 2]

Step 1: Counting Parity with Counters

  • For array a, convert each element's binary form:

    • 3 in binary is 11, which has 2 set bits (even), so parity is 0.
    • 5 in binary is 101, which has 2 set bits (even), so parity is 0.

    cnt1 = Counter({0: 2}) because both 3 and 5 have even parity.

  • For array b:

    • 7 in binary is 111, which has 3 set bits (odd), so parity is 1.
    • 1 in binary is 1, which has 1 set bit (odd), so parity is 1.

    cnt2 = Counter({1: 2}) because both 7 and 1 have odd parity.

  • For array c:

    • 6 in binary is 110, which has 2 set bits (even), so parity is 0.
    • 2 in binary is 10, which has 1 set bit (odd), so parity is 1.

    cnt3 = Counter({0: 1, 1: 1}) as 6 has even and 2 has odd parity.

Step 2: Iterate Over Parity Combinations

  • Iterate over combinations of i, j, k where each can be 0 or 1, and compute if the combination results in an even sum of set bits using (i + j + k) & 1 ^ 1.

Step 3: Conditional Check and Accumulation

  • Check combinations:
    • i = 0, j = 1, k = 1: (0 + 1 + 1) & 1 ^ 1 = 0, not valid.
    • i = 0, j = 1, k = 0: (0 + 1 + 0) & 1 ^ 1 = 1, valid. Count this as cnt1[0] * cnt2[1] * cnt3[0] = 2 * 2 * 1 = 4.
    • Similarly check and find combinations.

After all combinations, the valid triplets are those resulting in i + j + k being even.

Step 4: Return Result

  • After accumulating valid triplet counts, the answer ans is 4.

Thus, for the example, there are 4 triplets that meet the criteria.

Solution Implementation

1from collections import Counter
2from typing import List
3
4class Solution:
5    def tripletCount(self, a: List[int], b: List[int], c: List[int]) -> int:
6        # Count how many numbers in each list have an odd or even number of 1s in their binary representation
7        count_a = Counter(x.bit_count() & 1 for x in a)
8        count_b = Counter(x.bit_count() & 1 for x in b)
9        count_c = Counter(x.bit_count() & 1 for x in c)
10      
11        result = 0
12      
13        # Iterate over all possible combinations of parity (odd/even)
14        for i in range(2):  # i can be 0 (even) or 1 (odd)
15            for j in range(2):  # j can be 0 (even) or 1 (odd)
16                for k in range(2):  # k can be 0 (even) or 1 (odd)
17                    # Check if the sum is even
18                    if (i + j + k) & 1 == 0:
19                        # Increment the result by the product of the counts for this combination
20                        result += count_a[i] * count_b[j] * count_c[k]
21      
22        return result
23
1class Solution {
2    public int tripletCount(int[] a, int[] b, int[] c) {
3        // Arrays to count the number of integers with even and odd number of set bits in each array
4        int[] countA = new int[2];
5        int[] countB = new int[2];
6        int[] countC = new int[2];
7
8        // Count the number of integers with odd and even number of 1-bits for array a
9        for (int x : a) {
10            int bitCount = Integer.bitCount(x) & 1;
11            ++countA[bitCount];
12        }
13
14        // Count the number of integers with odd and even number of 1-bits for array b
15        for (int x : b) {
16            int bitCount = Integer.bitCount(x) & 1;
17            ++countB[bitCount];
18        }
19
20        // Count the number of integers with odd and even number of 1-bits for array c
21        for (int x : c) {
22            int bitCount = Integer.bitCount(x) & 1;
23            ++countC[bitCount];
24        }
25
26        int result = 0;
27
28        // Iterate through all possible combinations of counts (even=0, odd=1)
29        for (int i = 0; i < 2; ++i) {
30            for (int j = 0; j < 2; ++j) {
31                for (int k = 0; k < 2; ++k) {
32                    // Check if the sum of indices is even
33                    if ((i + j + k) % 2 == 0) {
34                        // Add the product of counts for the current combination to the result
35                        result += countA[i] * countB[j] * countC[k];
36                    }
37                }
38            }
39        }
40      
41        return result;
42    }
43}
44
1#include <vector>
2
3class Solution {
4public:
5    int tripletCount(std::vector<int>& a, std::vector<int>& b, std::vector<int>& c) {
6        // Initialize counters for even and odd popcounts
7        int cntA[2] = {};
8        int cntB[2] = {};
9        int cntC[2] = {};
10      
11        // Count how many numbers in 'a' have even and odd popcounts
12        for (int num : a) {
13            ++cntA[__builtin_popcount(num) & 1];
14        }
15      
16        // Count how many numbers in 'b' have even and odd popcounts
17        for (int num : b) {
18            ++cntB[__builtin_popcount(num) & 1];
19        }
20      
21        // Count how many numbers in 'c' have even and odd popcounts
22        for (int num : c) {
23            ++cntC[__builtin_popcount(num) & 1];
24        }
25      
26        int result = 0;
27      
28        // Calculate the number of valid triplets (a, b, c) such that
29        // the sum of popcounts' parities is even
30        for (int i = 0; i < 2; ++i) {
31            for (int j = 0; j < 2; ++j) {
32                for (int k = 0; k < 2; ++k) {
33                    if ((i + j + k) % 2 == 0) {
34                        result += cntA[i] * cntB[j] * cntC[k];
35                    }
36                }
37            }
38        }
39      
40        return result;
41    }
42};
43
1// This function calculates the number of valid triplets (x, y, z) such that the sum of bits is even.
2function tripletCount(a: number[], b: number[], c: number[]): number {
3    // Initialize counters for odd and even bit-count elements in each array.
4    const cnt1: [number, number] = [0, 0];
5    const cnt2: [number, number] = [0, 0];
6    const cnt3: [number, number] = [0, 0];
7
8    // Populate cnt1 with parity counts for array 'a'.
9    for (const x of a) {
10        cnt1[bitCount(x) & 1]++;
11    }
12
13    // Populate cnt2 with parity counts for array 'b'.
14    for (const x of b) {
15        cnt2[bitCount(x) & 1]++;
16    }
17
18    // Populate cnt3 with parity counts for array 'c'.
19    for (const x of c) {
20        cnt3[bitCount(x) & 1]++;
21    }
22
23    let ans = 0;
24
25    // Check each combination of parity (odd/even) counts and accumulate the number of triplets
26    // where the sum of bits is even.
27    for (let i = 0; i < 2; ++i) {
28        for (let j = 0; j < 2; ++j) {
29            for (let k = 0; k < 2; ++k) {
30                if ((i + j + k) % 2 === 0) {
31                    ans += cnt1[i] * cnt2[j] * cnt3[k];
32                }
33            }
34        }
35    }
36
37    return ans; // Return the total count of valid triplets.
38}
39
40// This function calculates the number of set bits (1s) in the binary representation of an integer.
41function bitCount(value: number): number {
42    // Use bit manipulation techniques to efficiently count set bits.
43    value = value - ((value >>> 1) & 0x55555555);
44    value = (value & 0x33333333) + ((value >>> 2) & 0x33333333);
45    value = (value + (value >>> 4)) & 0x0f0f0f0f;
46    value = value + (value >>> 8);
47    value = value + (value >>> 16);
48    return value & 0x3f; // Mask to get the final count of set bits.
49}
50

Time and Space Complexity

The time complexity of the code is O(n), where n is the combined length of arrays a, b, and c. This is because each element in these arrays is processed exactly once to calculate the bit count parity and to populate the counters.

The space complexity of the code is O(1). The Counter objects cnt1, cnt2, and cnt3 only store counts for at most 2 distinct values (0 or 1) based on the parity of the bit count, meaning they do not grow with the size of the input arrays.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

How many ways can you arrange the three letters A, B and C?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More