Facebook Pixel

2917. Find the K-or of an Array

EasyBit ManipulationArray
Leetcode Link

Problem Description

You are given an integer array nums and an integer k. The problem introduces a new operation called K-or, which is an extension of the standard bitwise OR operation.

In the K-or operation, a bit position in the result is set to 1 if at least k numbers in the array have a 1 in that bit position.

Your task is to return the K-or of the array nums.

How K-or works:

  1. Look at each bit position across all numbers in the array
  2. Count how many numbers have a 1 in that specific bit position
  3. If the count is greater than or equal to k, set that bit to 1 in the result
  4. Otherwise, set that bit to 0 in the result

Example walkthrough:

For nums = [7,12,9,8,9,15] and k = 4:

  • In binary: 7 = 0111, 12 = 1100, 9 = 1001, 8 = 1000, 9 = 1001, 15 = 1111
  • Bit 0 (rightmost): appears as 1 in numbers 7, 9, 9, 15 → count = 4 ≥ k, so bit 0 is set
  • Bit 1: appears as 1 in numbers 7, 15 → count = 2 < k, so bit 1 is not set
  • Bit 2: appears as 1 in numbers 7, 12, 15 → count = 3 < k, so bit 2 is not set
  • Bit 3: appears as 1 in numbers 12, 9, 8, 9, 15 → count = 5 ≥ k, so bit 3 is set
  • Result: 1001 in binary = 9 in decimal

Special cases:

  • When k = 1, the K-or equals the regular bitwise OR of all elements
  • When k = nums.length, a bit is set only if it appears in ALL numbers

The solution iterates through each of the 32 bit positions (since numbers can be up to 2^31 - 1), counts how many numbers have that bit set using x >> i & 1, and if the count meets the threshold k, sets that bit in the answer using ans |= 1 << i.

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

Intuition

The key insight is that we need to examine each bit position independently. Since the K-or operation determines each bit of the result based solely on how many input numbers have that bit set, we can process each bit position separately.

Think of it this way: for a regular OR operation, a bit is set if any number has it set. For K-or, we're extending this concept - a bit is set if at least k numbers have it set. This naturally leads us to count occurrences for each bit position.

Since we're dealing with 32-bit integers (constraint: nums[i] < 2^31), we only need to check 32 bit positions. For each position i from 0 to 31:

  1. Count how many numbers have bit i set
  2. If this count meets our threshold k, include this bit in our result

To check if bit i is set in a number x, we use the bit manipulation technique (x >> i) & 1:

  • x >> i shifts the number right by i positions, bringing bit i to the rightmost position
  • & 1 masks everything except the rightmost bit, giving us either 0 or 1

To set bit i in our answer, we use ans |= (1 << i):

  • 1 << i creates a number with only bit i set
  • |= performs OR assignment, adding this bit to our result

This approach is efficient because:

  • We make a single pass through each bit position (32 iterations)
  • For each bit, we scan the array once (n elements)
  • Total time complexity is O(32 * n) = O(n), which is optimal since we must examine every number at least once

Solution Approach

The solution uses a bit manipulation approach with enumeration of bit positions. Here's how the implementation works:

Algorithm Steps:

  1. Initialize ans = 0 to store our result
  2. Iterate through each bit position i from 0 to 31 (covering all possible bits in a 32-bit integer)
  3. For each bit position i:
    • Count how many numbers in nums have bit i set using sum(x >> i & 1 for x in nums)
    • If this count is greater than or equal to k, set bit i in our answer

Detailed Implementation Walkthrough:

def findKOr(self, nums: List[int], k: int) -> int:
    ans = 0
    for i in range(32):
        cnt = sum(x >> i & 1 for x in nums)
        if cnt >= k:
            ans |= 1 << i
    return ans

Line-by-line Explanation:

  • ans = 0: Start with all bits set to 0
  • for i in range(32): Check each of the 32 possible bit positions
  • cnt = sum(x >> i & 1 for x in nums):
    • For each number x in the array
    • x >> i shifts x right by i positions
    • & 1 extracts the least significant bit (which was originally at position i)
    • sum() counts total numbers with bit i set
  • if cnt >= k: Check if at least k numbers have this bit set
  • ans |= 1 << i: If condition met, set bit i in the answer
    • 1 << i creates a number with only bit i set (e.g., 1 << 3 = 1000 in binary = 8)
    • |= performs bitwise OR assignment to add this bit to our result

Example Trace with nums = [7,12,9,8,9,15], k = 4:

  • i = 0: cnt = 4 (from 7,9,9,15) ≥ 4, so ans |= 1 → ans = 1
  • i = 1: cnt = 2 (from 7,15) < 4, skip
  • i = 2: cnt = 3 (from 7,12,15) < 4, skip
  • i = 3: cnt = 5 (from 12,9,8,9,15) ≥ 4, so ans |= 8 → ans = 9
  • Final result: 9

Time and Space Complexity:

  • Time: O(32 × n) = O(n), where n is the length of nums
  • Space: O(1), only using a constant amount of extra space

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 a simple example with nums = [5, 3, 6] and k = 2.

First, let's convert our numbers to binary:

  • 5 = 0101
  • 3 = 0011
  • 6 = 0110

Now we'll check each bit position from right to left (positions 0 to 31, though we only need to check up to position 2 for this example):

Bit Position 0 (rightmost bit):

  • 5 = 0101 → has bit 0 set
  • 3 = 0011 → has bit 0 set
  • 6 = 0110 → does not have bit 0 set
  • Count = 2, which is ≥ k (2), so bit 0 is set in result

Bit Position 1:

  • 5 = 0101 → does not have bit 1 set
  • 3 = 0011 → has bit 1 set
  • 6 = 0110 → has bit 1 set
  • Count = 2, which is ≥ k (2), so bit 1 is set in result

Bit Position 2:

  • 5 = 0101 → has bit 2 set
  • 3 = 0011 → does not have bit 2 set
  • 6 = 0110 → has bit 2 set
  • Count = 2, which is ≥ k (2), so bit 2 is set in result

Building the result:

  • Start with ans = 0
  • Bit 0 qualifies: ans |= (1 << 0) → ans = 0001 = 1
  • Bit 1 qualifies: ans |= (1 << 1) → ans = 0011 = 3
  • Bit 2 qualifies: ans |= (1 << 2) → ans = 0111 = 7

The K-or result is 7.

To verify: In binary, our result is 0111, which means bits 0, 1, and 2 are all set - exactly the bits where at least 2 numbers had that bit set.

Solution Implementation

1class Solution:
2    def findKOr(self, nums: List[int], k: int) -> int:
3        """
4        Find the bitwise OR of all integers that appear in at least k elements.
5      
6        For each bit position, if at least k numbers have that bit set to 1,
7        then that bit should be set to 1 in the result.
8      
9        Args:
10            nums: List of integers
11            k: Minimum count threshold
12          
13        Returns:
14            The K-OR value of the array
15        """
16        result = 0
17      
18        # Check each bit position (0 to 31 for 32-bit integers)
19        for bit_position in range(32):
20            # Count how many numbers have the current bit set to 1
21            count_with_bit_set = sum(
22                (num >> bit_position) & 1 
23                for num in nums
24            )
25          
26            # If at least k numbers have this bit set, 
27            # set this bit in the result
28            if count_with_bit_set >= k:
29                result |= (1 << bit_position)
30      
31        return result
32
1class Solution {
2    public int findKOr(int[] nums, int k) {
3        int result = 0;
4      
5        // Check each bit position from 0 to 31 (32-bit integer)
6        for (int bitPosition = 0; bitPosition < 32; bitPosition++) {
7            int count = 0;
8          
9            // Count how many numbers have the current bit set to 1
10            for (int number : nums) {
11                // Right shift by bitPosition and check if the least significant bit is 1
12                count += (number >> bitPosition) & 1;
13            }
14          
15            // If at least k numbers have this bit set, include it in the result
16            if (count >= k) {
17                // Set the bit at bitPosition in the result
18                result |= (1 << bitPosition);
19            }
20        }
21      
22        return result;
23    }
24}
25
1class Solution {
2public:
3    int findKOr(vector<int>& nums, int k) {
4        int result = 0;
5      
6        // Check each bit position from 0 to 31 (32-bit integer)
7        for (int bitPosition = 0; bitPosition < 32; ++bitPosition) {
8            int countOnes = 0;
9          
10            // Count how many numbers have 1 at the current bit position
11            for (int number : nums) {
12                // Right shift by bitPosition and check if the least significant bit is 1
13                countOnes += (number >> bitPosition) & 1;
14            }
15          
16            // If at least k numbers have 1 at this bit position,
17            // set this bit in the result
18            if (countOnes >= k) {
19                result |= (1 << bitPosition);
20            }
21        }
22      
23        return result;
24    }
25};
26
1/**
2 * Finds the K-OR of an array where each bit position in the result is set to 1
3 * if at least k numbers in the array have that bit set to 1
4 * @param nums - Array of non-negative integers
5 * @param k - Minimum count threshold for setting a bit in the result
6 * @returns The K-OR value of the array
7 */
8function findKOr(nums: number[], k: number): number {
9    let result: number = 0;
10  
11    // Check each bit position (0 to 31 for 32-bit integers)
12    for (let bitPosition: number = 0; bitPosition < 32; bitPosition++) {
13        let bitCount: number = 0;
14      
15        // Count how many numbers have the current bit set to 1
16        for (const num of nums) {
17            // Right shift by bitPosition and check if the least significant bit is 1
18            bitCount += (num >> bitPosition) & 1;
19        }
20      
21        // If at least k numbers have this bit set, set it in the result
22        if (bitCount >= k) {
23            // Set the bit at bitPosition in the result using OR operation
24            result |= 1 << bitPosition;
25        }
26    }
27  
28    return result;
29}
30

Time and Space Complexity

Time Complexity: O(32 × n) which simplifies to O(n), where n is the length of the array nums.

The algorithm iterates through 32 bit positions (since we're checking 32-bit integers), and for each bit position, it iterates through all n elements in the array to count how many numbers have that bit set. The inner sum operation sum(x >> i & 1 for x in nums) takes O(n) time, and this is executed 32 times, resulting in O(32 × n) = O(n).

Note that the reference answer mentions O(n × log M) where M is the maximum value in nums. This is essentially equivalent because log M represents the number of bits needed to represent the maximum value. For 32-bit integers, this is at most 32, so O(n × 32) = O(n × log M) when considering M as the maximum possible value.

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space. The variables ans, i, and cnt are the only additional storage used, regardless of the input size. The generator expression in the sum function doesn't create a list but evaluates lazily, so no additional space proportional to the input size is required.

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

Common Pitfalls

1. Incorrect Bit Range Assumption

A common mistake is assuming that checking 32 bits is always sufficient or necessary. While the problem states numbers can be up to 2^31 - 1, developers might:

  • Use an insufficient range (e.g., only checking 16 bits)
  • Use an excessive range unnecessarily (e.g., checking 64 bits when not needed)

Solution: Stick to 32 bits for standard integer problems, or dynamically determine the maximum bit length if optimization is critical:

max_bit_length = max(nums).bit_length() if nums else 0
for bit_position in range(max_bit_length):
    # ... rest of the logic

2. Misunderstanding Bit Extraction Logic

The expression (num >> bit_position) & 1 can be confusing. Common errors include:

  • Writing num & (1 << bit_position) without converting to 0 or 1
  • Using num >> bit_position % 2 which has different operator precedence

Solution: Always use parentheses for clarity and ensure the result is normalized to 0 or 1:

# Correct approaches:
bit_is_set = (num >> bit_position) & 1  # Returns 0 or 1
# OR
bit_is_set = 1 if (num & (1 << bit_position)) else 0

3. Off-by-One Error with Threshold

Developers might incorrectly implement the threshold check as count > k instead of count >= k, missing cases where exactly k numbers have the bit set.

Solution: Always use >= for "at least k" conditions:

if count_with_bit_set >= k:  # Correct
    result |= (1 << bit_position)

4. Integer Overflow in Other Languages

While Python handles arbitrary precision integers automatically, implementing this in languages like Java or C++ requires careful consideration of integer overflow when using bit shifts.

Solution for other languages: Use appropriate data types:

// Java example
long result = 0;
result |= (1L << bit_position);  // Use 1L for long literal

5. Inefficient Bit Counting

Some might try to convert numbers to binary strings and count '1's, which is inefficient:

# Inefficient approach - avoid this:
for i in range(32):
    count = sum(1 for num in nums if bin(num)[2:].zfill(32)[31-i] == '1')

Solution: Always use bitwise operations for efficiency:

# Efficient approach:
count = sum((num >> bit_position) & 1 for num in nums)
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the two traversal algorithms (BFS and DFS) can be used to find whether two nodes are connected?


Recommended Readings

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

Load More