Facebook Pixel

3094. Guess the Number Using Bitwise Questions II 🔒

MediumBit ManipulationInteractive
Leetcode Link

Problem Description

You are tasked with finding a number n that initially ranges between 0 and 2^30 - 1. This number n can be dynamically altered with every interaction using a pre-defined API function, commonBits(int num). The goal is to determine the initial value of n.

The commonBits(int num) function works in the following manner:

  • It calculates the number of bit positions where both n and num share the same value.
  • Then it updates n by applying an XOR operation between n and num.
  • Finally, it returns the count of common bits.

Each time you invoke this function, the API produces an effect on n, adding to the challenge of determining its initial value.

The constraints are as follows:

  • Both n and num are within the range of 0 to 2^30 - 1.
  • Requests for num out of the specified range will result in unreliable outputs.

Intuition

The solution is built on understanding how bit manipulation works in conjunction with the commonBits function. The key observations are:

  1. If commonBits is called twice with the same number, the net effect on n is neutral; its value remains unchanged after the second call.

  2. For a given bit position i, when we call commonBits(1 << i), we toggle the i-th bit of n. If this bit in n was originally 1, it becomes 0 after the call, and vice versa.

By using this behavior, the solution can efficiently determine the initial value for each bit:

  • For each bit i, use 1 << i to interact with the commonBits function.
  • Call commonBits(1 << i) twice to ascertain the state of the i-th bit.
  • Compare the results: if the first call results in count1 being greater than the second call count2, it indicates the i-th bit of the initial n was 1; otherwise, it was 0.

This approach efficiently reconstructs the original number n by analyzing each bit position using simple bitwise operations.

Solution Approach

The solution approach utilizes bit manipulation and is based on the properties of the commonBits function. The algorithm effectively reconstructs the initial number n through a series of bitwise operations. Here’s a detailed walkthrough of the implementation:

  1. Initialize a Variable for n:

    • Start with n = 0, which will be used to accumulate the bits of the original number.
  2. Loop Through Each Bit Position:

    • A loop iterates through bit positions from 0 to 31. Even though the range only requires up to 2^30 - 1, checking all bits ensures we handle potential edge cases at the boundaries.
  3. Call commonBits Twice Per Bit Position:

    • For each bit position i, use 1 << i to create a mask that isolates that specific bit.
    • Call commonBits(1 << i) twice:
      • count1 = commonBits(1 << i): This call toggles the i-th bit of n and returns the count of matching bits before toggling.
      • count2 = commonBits(1 << i): The second call toggles the i-th bit back to its original state and returns the new count of matching bits.
  4. Determine the Bit Value for the Original n:

    • Compare count1 with count2:
      • If count1 > count2, it implies the i-th bit in the original n was 1.
      • Else, the i-th bit was 0.
  5. Update the Value of n:

    • If the i-th bit is determined to be 1, use bitwise OR to set the i-th bit in n:
      n |= 1 << i
  6. Return the Reconstructed n:

    • After the loop completes, n will have been reconstructed to match its initial value before any calls to commonBits.

This bit manipulation strategy efficiently determines each bit in constant time per bit, resulting in an overall time complexity of (O(1)), as the number of bits is fixed.

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

To illustrate the solution approach, consider a scenario where the initial number n is 6, which in binary is 110. We want to reconstruct n using the commonBits function.

  1. Initialization:

    • Start with n = 0. This will gradually be transformed into the initial value of n through bit manipulation.
  2. Iterate Through Bit Positions (0 to 31):

    • We'll focus on bit positions relevant to 6, which are 0, 1, and 2.
  3. Processing Each Bit:

    • Bit Position 0:

      • Call commonBits(1 << 0) twice.
      • Before the first call, n = 110 and num = 001. Result: count1 = 1 (bit 0 matches).
      • After XOR operation, n = 111.
      • Second call with 1 << 0:
        • n = 111 and num = 001. Result: count2 = 2 (bits 1 and 2 match).
      • Since count1 < count2, the original 0-th bit is 0.
    • Bit Position 1:

      • Call commonBits(1 << 1) twice.
      • Before the first call, n = 110 and num = 010. Result: count1 = 2 (bits 1 and 2 match).
      • After XOR operation, n = 100.
      • Second call with 1 << 1:
        • n = 100 and num = 010. Result: count2 = 1 (bit 2 matches).
      • Since count1 > count2, the original 1-st bit is 1.
      • Update n as n |= 1 << 1n = 010 in binary, which is 2 in decimal.
    • Bit Position 2:

      • Call commonBits(1 << 2) twice.
      • Before the first call, n = 110 and num = 100. Result: count1 = 2 (bits 1 and 2 match).
      • After XOR operation, n = 010.
      • Second call with 1 << 2:
        • n = 010 and num = 100. Result: count2 = 1 (bit 1 matches).
      • Since count1 > count2, the original 2-nd bit is 1.
      • Update n as n |= 1 << 2n = 110 in binary, which is 6 in decimal.
  4. Final Result:

    • After processing each relevant bit, the reconstructed n is 6, which matches the initial value.

This walkthrough demonstrates how to use the commonBits function and bit manipulation to efficiently reconstruct the original number.

Solution Implementation

1# Definition of commonBits API.
2# def commonBits(num: int) -> int:
3
4
5class Solution:
6    def findNumber(self) -> int:
7        # Initialize the variable `n` which will hold the result number.
8        n = 0
9      
10        # Loop through each bit position from 0 to 31.
11        for i in range(32):
12            # Query the number of integers with common bits set at the i-th position.
13            count1 = commonBits(1 << i)
14            # The second query for the sake of demonstration, but it seems redundant.
15            # If this is intended for comparison, it could make sense to modify any conditions.
16            count2 = commonBits(1 << i)
17          
18            # Check if the count of numbers with the i-th bit set is greater than count2.
19            # Depending on the context of `commonBits`, this condition can vary.
20            if count1 > count2:
21                # Set the i-th bit of `n` to 1, effectively adjusting `n`.
22                n |= 1 << i
23              
24        # Return the computed number.
25        return n
26
1/**
2 * Definition of commonBits API (defined in the parent class Problem).
3 * int commonBits(int num);
4 */
5
6public class Solution extends Problem {
7    public int findNumber() {
8        int n = 0; // This will hold the number we are trying to find
9      
10        // Iterate over each bit position from 0 to 31 (since integers are usually 32 bits)
11        for (int i = 0; i < 32; ++i) {
12            // Check the number of common bits for current bit position
13            int count1 = commonBits(1 << i);
14            int count2 = commonBits(1 << i);
15          
16            // If count1 is greater than count2, it indicates the bit at position 'i' might be set
17            // in the number we are looking for
18            if (count1 > count2) {
19                n |= 1 << i; // Set the 'i-th' bit in 'n'
20            }
21        }
22      
23        return n; // Return the constructed number
24    }
25}
26
1/**
2 * Definition of the commonBits API, which is already provided.
3 * int commonBits(int num);
4 */
5
6class Solution {
7public:
8    int findNumber() {
9        int n = 0; // Initialize the result number to 0
10        for (int i = 0; i < 32; ++i) {
11            // Query the number of 1s when the i-th bit is set to 1.
12            int count1 = commonBits(1 << i);
13            // Query again to get the number of 1s when the i-th bit is set to 1.
14            // Note: Seems redundant, typically you'd compare `commonBits(n)` vs `commonBits(n | (1 << i))`
15            int count2 = commonBits(1 << i);
16          
17            // If the count from the first query is greater, set the i-th bit of n
18            if (count1 > count2) {
19                n |= 1 << i; // Use bitwise OR to set the i-th bit
20            }
21        }
22        return n; // Return the constructed number
23    }
24};
25
1/**
2 * Definition of the commonBits function, which is already provided.
3 * function commonBits(num: number): number;
4 */
5
6// Global function to find the number using the commonBits API.
7function findNumber(): number {
8    let n = 0; // Initialize the result number to 0.
9  
10    // Iterate over each bit position from 0 to 31 (assuming a 32-bit integer).
11    for (let i = 0; i < 32; ++i) {
12        // Calculate the value with only the i-th bit set to 1.
13        const bitMask = 1 << i;
14      
15        // Query the number of 1s when the i-th bit is set to 1.
16        const count1 = commonBits(bitMask);
17      
18        // Query again to confirm the result, checking the same bit mask.
19        const count2 = commonBits(bitMask);
20
21        // If the count from the first query is greater, set the i-th bit of n.
22        // However, in typical scenarios, you'd compare to `commonBits(n | bitMask)`.
23        if (count1 > count2) {
24            n |= bitMask; // Use bitwise OR to set the i-th bit.
25        }
26    }
27  
28    return n; // Return the constructed number.
29}
30

Time and Space Complexity

The time complexity of the provided code is O(32), which simplifies to O(1) as the loop runs a constant number of times (32 iterations). Each iteration involves calling the commonBits function twice, which is assumed to run in constant time.

The space complexity is O(1) because the amount of extra space used by the algorithm does not depend on the size of the input. The operations and variables like n and constants used within the loop occupy a fixed amount of space.

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

In a binary min heap, the maximum element can be found in:


Recommended Readings

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


Load More