Facebook Pixel

982. Triples with Bitwise AND Equal To Zero

HardBit ManipulationArrayHash Table
Leetcode Link

Problem Description

You are given an integer array nums. Your task is to count the number of AND triples.

An AND triple is a set of three indices (i, j, k) that satisfy the following conditions:

  • All three indices i, j, and k must be valid positions in the array (between 0 and nums.length - 1)
  • The bitwise AND operation of the three elements at these positions must equal zero: nums[i] & nums[j] & nums[k] == 0

The & operator represents the bitwise AND operation, which compares each bit position of the numbers and returns 1 only if both bits are 1, otherwise returns 0.

For example, if nums = [2, 1, 3]:

  • The triple (0, 1, 2) gives us 2 & 1 & 3 = 0, so this is a valid AND triple
  • We need to check all possible combinations of three indices

Note that the indices don't need to be distinct - you can use the same index multiple times in a triple. For instance, (0, 0, 1) is a valid triple if nums[0] & nums[0] & nums[1] == 0.

Return the total count of all valid AND triples.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The naive approach would be to check all possible triples (i, j, k) using three nested loops, computing nums[i] & nums[j] & nums[k] for each combination. However, this would require O(n³) operations, which could be inefficient for larger arrays.

The key insight is that we can optimize this by breaking down the problem into two stages:

  1. Pre-compute partial results: Instead of computing nums[i] & nums[j] & nums[k] for every triple, we can first compute all possible values of nums[i] & nums[j] for every pair (i, j). Since the bitwise AND operation is associative, we have (nums[i] & nums[j]) & nums[k] = nums[i] & nums[j] & nums[k].

  2. Count occurrences: We store how many times each partial result nums[i] & nums[j] appears. This is important because if multiple pairs produce the same AND result, they will all contribute to the answer when combined with a suitable third element.

  3. Match with third element: For each unique partial result xy from step 1, we check against every element z in the array. If xy & z == 0, then all pairs that produced xy can form valid triples with this z. So we add the count of such pairs to our answer.

This approach is more efficient because:

  • We avoid redundant calculations by storing intermediate results
  • We leverage counting to handle multiple occurrences of the same partial AND result
  • We effectively reduce the problem from checking combinations to for pre-computation plus checking at most n² × n conditions (but often much fewer due to the counting optimization)

The beauty of this solution lies in recognizing that many different pairs (i, j) might produce the same AND result, and all of them would behave identically when combined with any third element k.

Solution Approach

The implementation follows a two-phase approach using enumeration and counting:

Phase 1: Pre-compute all pairwise AND results

cnt = Counter(x & y for x in nums for y in nums)
  • We use a nested loop (via list comprehension) to iterate through all pairs of elements in nums
  • For each pair (x, y), we compute their bitwise AND: x & y
  • We use Python's Counter from the collections module to count how many times each AND result appears
  • For example, if nums = [2, 1, 3], we compute:
    • 2 & 2 = 2, 2 & 1 = 0, 2 & 3 = 2
    • 1 & 2 = 0, 1 & 1 = 1, 1 & 3 = 1
    • 3 & 2 = 2, 3 & 1 = 1, 3 & 3 = 3
    • The counter would store: {2: 3, 0: 2, 1: 3, 3: 1}

Phase 2: Count valid triples

return sum(v for xy, v in cnt.items() for z in nums if xy & z == 0)
  • We iterate through each unique pairwise AND result xy and its count v from our counter
  • For each xy, we check every element z in the original array
  • If xy & z == 0, this means we found valid triples:
    • All v pairs that produced the AND result xy can form valid triples with this z
    • We add v to our running total
  • The sum accumulates all valid triple counts

Why this works:

  • If (nums[i] & nums[j]) & nums[k] == 0, then any indices (i', j') where nums[i'] & nums[j'] == nums[i] & nums[j] will also satisfy (nums[i'] & nums[j']) & nums[k] == 0
  • By grouping pairs by their AND result and counting them, we avoid redundant calculations
  • Time complexity: O(n²) for the first phase + O(n × unique_AND_results) for the second phase, which is better than the naive O(n³) approach

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's walk through the solution with nums = [2, 1, 3].

Step 1: Pre-compute all pairwise AND results

We need to compute x & y for every pair of elements (including pairs with the same element):

  • For x = 2 (binary: 10):

    • 2 & 2 = 2 (10 & 10 = 10)
    • 2 & 1 = 0 (10 & 01 = 00)
    • 2 & 3 = 2 (10 & 11 = 10)
  • For x = 1 (binary: 01):

    • 1 & 2 = 0 (01 & 10 = 00)
    • 1 & 1 = 1 (01 & 01 = 01)
    • 1 & 3 = 1 (01 & 11 = 01)
  • For x = 3 (binary: 11):

    • 3 & 2 = 2 (11 & 10 = 10)
    • 3 & 1 = 1 (11 & 01 = 01)
    • 3 & 3 = 3 (11 & 11 = 11)

Our Counter becomes: {0: 2, 1: 3, 2: 3, 3: 1}

  • AND result 0 appears 2 times (from pairs at indices (0,1) and (1,0))
  • AND result 1 appears 3 times (from pairs at indices (1,1), (1,2), (2,1))
  • AND result 2 appears 3 times (from pairs at indices (0,0), (0,2), (2,0))
  • AND result 3 appears 1 time (from pair at indices (2,2))

Step 2: Count valid triples

Now for each unique AND result and its count, check against every element in nums:

  • For xy = 0 (count = 2):

    • Check 0 & 2 = 0 ✓ → Add 2 to answer
    • Check 0 & 1 = 0 ✓ → Add 2 to answer
    • Check 0 & 3 = 0 ✓ → Add 2 to answer
    • Subtotal: 6
  • For xy = 1 (count = 3):

    • Check 1 & 2 = 0 ✓ → Add 3 to answer
    • Check 1 & 1 = 1 ✗ → Add 0
    • Check 1 & 3 = 1 ✗ → Add 0
    • Subtotal: 3
  • For xy = 2 (count = 3):

    • Check 2 & 2 = 2 ✗ → Add 0
    • Check 2 & 1 = 0 ✓ → Add 3 to answer
    • Check 2 & 3 = 2 ✗ → Add 0
    • Subtotal: 3
  • For xy = 3 (count = 1):

    • Check 3 & 2 = 2 ✗ → Add 0
    • Check 3 & 1 = 1 ✗ → Add 0
    • Check 3 & 3 = 3 ✗ → Add 0
    • Subtotal: 0

Total: 6 + 3 + 3 + 0 = 12

This means there are 12 valid AND triples where nums[i] & nums[j] & nums[k] == 0.

Solution Implementation

1class Solution:
2    def countTriplets(self, nums: List[int]) -> int:
3        # Step 1: Pre-compute frequency of all possible bitwise AND results for pairs
4        # For each pair (x, y) from nums, calculate x & y and count occurrences
5        pair_and_frequency = Counter(x & y for x in nums for y in nums)
6      
7        # Step 2: Count valid triplets
8        # For each pre-computed pair AND result and its frequency,
9        # check against each number z in nums
10        # If (x & y) & z == 0, then the triplet (x, y, z) has AND result of 0
11        triplet_count = sum(
12            frequency 
13            for pair_and_result, frequency in pair_and_frequency.items() 
14            for z in nums 
15            if pair_and_result & z == 0
16        )
17      
18        return triplet_count
19
1class Solution {
2    /**
3     * Counts the number of triplets (i, j, k) where nums[i] & nums[j] & nums[k] == 0.
4     * Uses a two-step approach: first precompute all possible pairs' AND results,
5     * then check which values when ANDed with the precomputed results give 0.
6     * 
7     * @param nums the input array of integers
8     * @return the count of valid triplets
9     */
10    public int countTriplets(int[] nums) {
11        // Find the maximum value in the array to determine the size of frequency array
12        int maxValue = 0;
13        for (int num : nums) {
14            maxValue = Math.max(maxValue, num);
15        }
16      
17        // Create frequency array to store count of all possible AND results of pairs
18        // frequencyCount[i] represents how many pairs (x, y) have x & y = i
19        int[] frequencyCount = new int[maxValue + 1];
20      
21        // Precompute all possible pairs' AND results and their frequencies
22        // This handles the first two elements of the triplet
23        for (int firstNum : nums) {
24            for (int secondNum : nums) {
25                int andResult = firstNum & secondNum;
26                frequencyCount[andResult]++;
27            }
28        }
29      
30        // Count valid triplets by checking each precomputed pair result with third element
31        int tripletCount = 0;
32      
33        // Iterate through all possible pair AND results
34        for (int pairAndResult = 0; pairAndResult <= maxValue; pairAndResult++) {
35            // Check if this pair result ANDed with any third element gives 0
36            for (int thirdNum : nums) {
37                if ((pairAndResult & thirdNum) == 0) {
38                    // Add the frequency of this pair result to the total count
39                    tripletCount += frequencyCount[pairAndResult];
40                }
41            }
42        }
43      
44        return tripletCount;
45    }
46}
47
1class Solution {
2public:
3    int countTriplets(vector<int>& nums) {
4        // Find the maximum value in the array to determine the upper bound
5        int maxValue = ranges::max(nums);
6      
7        // Create a frequency array to store count of all possible AND results
8        // between pairs of elements from nums
9        int frequency[maxValue + 1];
10        memset(frequency, 0, sizeof(frequency));
11      
12        // Count occurrences of all possible (nums[i] & nums[j]) values
13        // This preprocessing step calculates AND for all pairs
14        for (int& num1 : nums) {
15            for (int& num2 : nums) {
16                frequency[num1 & num2]++;
17            }
18        }
19      
20        // Count valid triplets where (nums[i] & nums[j] & nums[k]) == 0
21        int result = 0;
22      
23        // Iterate through all possible AND values from the frequency array
24        for (int andResult = 0; andResult <= maxValue; ++andResult) {
25            // For each element in nums, check if it forms a valid triplet
26            // with the current AND result
27            for (int& num : nums) {
28                // If (andResult & num) == 0, then all triplets with
29                // (nums[i] & nums[j]) == andResult and nums[k] == num
30                // will satisfy the condition
31                if ((andResult & num) == 0) {
32                    result += frequency[andResult];
33                }
34            }
35        }
36      
37        return result;
38    }
39};
40
1/**
2 * Counts the number of triplets (i, j, k) where nums[i] & nums[j] & nums[k] == 0
3 * @param nums - Array of integers to find triplets from
4 * @returns Number of valid triplets where bitwise AND equals 0
5 */
6function countTriplets(nums: number[]): number {
7    // Find the maximum value in the array to determine the upper bound
8    const maxValue: number = Math.max(...nums);
9  
10    // Create a frequency array to store counts of all possible AND results between pairs
11    // countArray[value] = number of pairs (i, j) where nums[i] & nums[j] = value
12    const countArray: number[] = Array(maxValue + 1).fill(0);
13  
14    // Calculate all possible AND results for pairs of elements
15    // This pre-computation avoids redundant calculations later
16    for (const firstNum of nums) {
17        for (const secondNum of nums) {
18            countArray[firstNum & secondNum]++;
19        }
20    }
21  
22    // Initialize the result counter for valid triplets
23    let result: number = 0;
24  
25    // Iterate through all possible AND values from pairs
26    for (let pairAndValue: number = 0; pairAndValue <= maxValue; ++pairAndValue) {
27        // For each third element, check if it forms a valid triplet
28        for (const thirdNum of nums) {
29            // If (nums[i] & nums[j]) & nums[k] == 0, we found valid triplets
30            if ((pairAndValue & thirdNum) === 0) {
31                // Add the count of all pairs that have this AND value
32                result += countArray[pairAndValue];
33            }
34        }
35    }
36  
37    return result;
38}
39

Time and Space Complexity

The time complexity is O(n^2 + n × M), where n is the length of the array nums and M is the maximum value in the array nums (with M ≤ 2^16 in this problem).

Breaking down the time complexity:

  • The first part Counter(x & y for x in nums for y in nums) iterates through all pairs of elements in nums, performing a bitwise AND operation for each pair. This takes O(n^2) time.
  • The second part iterates through all key-value pairs in the counter (at most M unique values from the bitwise AND operations) and for each pair, iterates through all elements z in nums to check if xy & z == 0. This takes O(M × n) time.
  • Combined: O(n^2 + n × M)

The space complexity is O(M), where M is the maximum possible value in nums.

The space is primarily used by the Counter object cnt, which stores the frequency of each unique result from x & y. In the worst case, there could be up to M different values resulting from the bitwise AND operations between pairs of elements, hence O(M) space complexity.

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

Common Pitfalls

Pitfall 1: Misunderstanding the index requirement - treating indices as distinct

A common mistake is assuming that the three indices i, j, and k must all be different. The problem actually allows using the same index multiple times. For instance, (0, 0, 0) is a valid triple if nums[0] & nums[0] & nums[0] == 0.

Wrong approach:

# Incorrectly filtering out cases where indices are the same
count = 0
for i in range(len(nums)):
    for j in range(i+1, len(nums)):  # Wrong: skipping i == j
        for k in range(j+1, len(nums)):  # Wrong: skipping j == k
            if nums[i] & nums[j] & nums[k] == 0:
                count += 1

Correct approach:

# Allow all index combinations including duplicates
for x in nums:
    for y in nums:
        for z in nums:
            if x & y & z == 0:
                count += 1

Pitfall 2: Integer overflow concerns in other languages

While Python handles arbitrary-precision integers automatically, implementing this in languages like C++ or Java requires attention to data types. The bitwise AND operation itself won't overflow, but the counting might.

Solution for other languages:

  • Use appropriate data types (e.g., long long in C++ or long in Java) for the counter
  • The maximum count would be where n is the array length, so ensure your counter variable can handle this

Pitfall 3: Inefficient Counter implementation

Some might try to manually implement the counting logic instead of using Python's efficient Counter class, leading to verbose and potentially slower code.

Inefficient manual approach:

# Manual dictionary management
pair_and_frequency = {}
for x in nums:
    for y in nums:
        result = x & y
        if result in pair_and_frequency:
            pair_and_frequency[result] += 1
        else:
            pair_and_frequency[result] = 1

Better approach (as shown in solution):

# Concise and efficient using Counter
pair_and_frequency = Counter(x & y for x in nums for y in nums)

Pitfall 4: Attempting premature optimization with bit manipulation tricks

Some might try to optimize by analyzing bit patterns or using advanced bit manipulation techniques, but this often complicates the code without significant performance gains for this problem's constraints.

Example of over-optimization:

# Trying to skip combinations based on bit patterns
# This adds complexity without meaningful performance improvement
max_val = max(nums)
bit_positions = []
while max_val:
    bit_positions.append(max_val & 1)
    max_val >>= 1
# ... complex logic to prune combinations

The straightforward two-phase approach with O(n²) complexity is already optimal enough for typical constraints and much clearer to understand and maintain.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement recursion?


Recommended Readings

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

Load More