3314. Construct the Minimum Bitwise Array I
Problem Description
You are given an array nums
containing n
prime integers. Your task is to construct a new array ans
of the same length n
that satisfies a specific bitwise condition.
For each index i
, you need to find a value for ans[i]
such that when you perform a bitwise OR operation between ans[i]
and ans[i] + 1
, the result equals nums[i]
. In other words, the condition ans[i] OR (ans[i] + 1) == nums[i]
must hold true.
Additionally, among all possible values that satisfy this condition, you must choose the minimum value for each ans[i]
.
If no such value exists for a particular position that satisfies the condition, set ans[i] = -1
.
The key insight is that for any integer a
, the operation a OR (a + 1)
flips the rightmost 0
bit in a
to 1
(along with setting all bits to its right to 0
in a
and 1
in a+1
). This means the result is always odd. Therefore, if nums[i]
is even (which only happens when it equals 2
since all inputs are prime), no valid ans[i]
exists.
For odd values of nums[i]
, you need to find the smallest a
such that performing a OR (a + 1)
gives you nums[i]
. This involves identifying which bit in a
should be the rightmost 0
that gets flipped to produce the desired result.
Intuition
Let's first understand what happens when we perform a OR (a + 1)
. When we add 1 to a number a
, we're essentially flipping the rightmost 0
bit to 1
and all bits to its right become 0
. For example:
- If
a = 5 (0b101)
, thena + 1 = 6 (0b110)
- If
a = 11 (0b1011)
, thena + 1 = 12 (0b1100)
When we OR these two consecutive numbers, the result has a specific pattern: it sets the rightmost 0
bit of a
to 1
and keeps all other bits to the left unchanged, while all bits to the right of that position become 1
.
This means a OR (a + 1)
always produces an odd number (since the least significant bit is always 1
). Therefore, if our target nums[i]
is even, it's impossible to find such an a
. Since we're dealing with prime numbers, the only even prime is 2
, so we return -1
for this case.
For odd targets, we need to work backwards. Given that nums[i]
is the result of a OR (a + 1)
, we need to figure out what a
could be. The key observation is that nums[i]
has all 1
s up to a certain position (from the right), then continues with some pattern. The transition point tells us where the rightmost 0
bit in a
was located.
To find the minimum a
, we look for the first 0
bit in nums[i]
starting from position 1 (second least significant bit). Once we find this 0
at position i
, we know that the rightmost 0
in a
was at position i - 1
. To construct a
from nums[i]
, we need to flip the bit at position i - 1
from 1
to 0
. This can be done using XOR: a = nums[i] XOR (1 << (i - 1))
.
This approach guarantees we find the minimum valid a
because we're identifying the rightmost possible position for the 0
bit in a
, which gives us the smallest value that satisfies the condition.
Solution Approach
The implementation follows a straightforward approach based on our bit manipulation understanding:
-
Initialize Result Array: Create an empty array
ans
to store our results. -
Process Each Number: Iterate through each number
x
in the input arraynums
. -
Handle Even Prime Case: First check if
x == 2
. Since2
is the only even prime anda OR (a + 1)
always produces odd results, we append-1
to indicate no valid answer exists. -
Find the First Zero Bit: For odd primes, we need to find the position of the first
0
bit starting from index 1 (the second least significant bit). We iterate through bit positions from 1 to 31:- Check each bit using
x >> i & 1 ^ 1
, which evaluates totrue
when bit at positioni
is0
- The expression works by:
x >> i
shiftsx
right byi
positions& 1
isolates the least significant bit^ 1
flips the bit (XOR with 1), so0
becomes1
(true) and1
becomes0
(false)
- Check each bit using
-
Calculate the Answer: Once we find the first
0
bit at positioni
, we calculateans[i]
by flipping the bit at positioni - 1
inx
:- Use the formula:
x ^ (1 << (i - 1))
1 << (i - 1)
creates a mask with only the(i-1)
-th bit set to1
- XOR operation flips that specific bit in
x
from1
to0
- Break out of the loop once we find and process the first
0
bit
- Use the formula:
-
Return Result: After processing all numbers, return the completed
ans
array.
The algorithm runs in O(n * log(max(nums)))
time, where n
is the length of the input array and the log factor comes from checking up to 32 bits for each number. The space complexity is O(1)
extra space (not counting the output array).
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 the solution with nums = [3, 5, 7]
:
For nums[0] = 3 (binary: 0b011):
- Since 3 is odd, we look for a value
a
wherea OR (a+1) = 3
- Binary of 3 is
011
- we need to find the first0
bit starting from position 1 - Position 0: bit is
1
(skip) - Position 1: bit is
1
(skip) - Position 2: bit is
0
(found!) - Since the first
0
is at position 2, we flip the bit at position2-1 = 1
- Calculate:
3 XOR (1 << 1) = 011 XOR 010 = 001 = 1
- Verify:
1 OR 2 = 001 OR 010 = 011 = 3
✓ - So
ans[0] = 1
For nums[1] = 5 (binary: 0b101):
- 5 is odd, so we proceed
- Binary of 5 is
101
- find first0
bit from position 1 - Position 0: bit is
1
(skip) - Position 1: bit is
0
(found!) - Flip bit at position
1-1 = 0
- Calculate:
5 XOR (1 << 0) = 101 XOR 001 = 100 = 4
- Verify:
4 OR 5 = 100 OR 101 = 101 = 5
✓ - So
ans[1] = 4
For nums[2] = 7 (binary: 0b111):
- 7 is odd, so we proceed
- Binary of 7 is
111
- find first0
bit from position 1 - Position 0: bit is
1
(skip) - Position 1: bit is
1
(skip) - Position 2: bit is
1
(skip) - Position 3: bit is
0
(found!) - Flip bit at position
3-1 = 2
- Calculate:
7 XOR (1 << 2) = 111 XOR 100 = 011 = 3
- Verify:
3 OR 4 = 011 OR 100 = 111 = 7
✓ - So
ans[2] = 3
Final result: ans = [1, 4, 3]
Each answer represents the minimum value that, when OR'd with its successor, produces the corresponding prime in the input array.
Solution Implementation
1class Solution:
2 def minBitwiseArray(self, nums: List[int]) -> List[int]:
3 """
4 For each number in nums, find the minimum value ans[i] such that
5 ans[i] OR (ans[i] + 1) = nums[i], or -1 if no such value exists.
6
7 Args:
8 nums: List of integers to process
9
10 Returns:
11 List of minimum values or -1 for each number in nums
12 """
13 result = []
14
15 for num in nums:
16 # Special case: 2 has no valid answer
17 # Because 2 in binary is 10, and no value OR (value+1) can produce this
18 if num == 2:
19 result.append(-1)
20 else:
21 # Find the rightmost 0 bit in num (searching from bit position 1)
22 for bit_position in range(1, 32):
23 # Check if the bit at current position is 0
24 if ((num >> bit_position) & 1) == 0:
25 # Found the rightmost 0 bit
26 # XOR with 1 shifted to the previous bit position
27 # This effectively clears the bit before the found 0
28 answer = num ^ (1 << (bit_position - 1))
29 result.append(answer)
30 break
31
32 return result
33
1class Solution {
2 public int[] minBitwiseArray(List<Integer> nums) {
3 int n = nums.size();
4 int[] result = new int[n];
5
6 for (int i = 0; i < n; i++) {
7 int currentNum = nums.get(i);
8
9 // Special case: no valid answer exists for 2
10 // Because for any x, x | (x+1) cannot equal 2
11 if (currentNum == 2) {
12 result[i] = -1;
13 } else {
14 // Find the first 0 bit starting from position 1
15 // Then flip the bit at position (j-1) to get the minimum value
16 for (int bitPosition = 1; bitPosition < 32; bitPosition++) {
17 // Check if the bit at current position is 0
18 if ((currentNum >> bitPosition & 1) == 0) {
19 // XOR with 1 shifted left by (bitPosition - 1)
20 // This flips the bit at position (bitPosition - 1)
21 result[i] = currentNum ^ (1 << (bitPosition - 1));
22 break;
23 }
24 }
25 }
26 }
27
28 return result;
29 }
30}
31
1class Solution {
2public:
3 vector<int> minBitwiseArray(vector<int>& nums) {
4 vector<int> result;
5
6 for (int num : nums) {
7 // Special case: when num is 2, no valid answer exists
8 // This is because 2 in binary is 10, and no value y exists where y | (y+1) = 2
9 if (num == 2) {
10 result.push_back(-1);
11 } else {
12 // Find the minimum value y such that y | (y + 1) = num
13 // Strategy: Find the first 0 bit from position 1 onwards,
14 // then flip the bit at the previous position
15 for (int bitPosition = 1; bitPosition < 32; ++bitPosition) {
16 // Check if the bit at current position is 0
17 // (x >> i) & 1 gives the bit at position i
18 // ^ 1 inverts it, so we're checking if bit is 0
19 if (((num >> bitPosition) & 1) ^ 1) {
20 // Found first 0 bit at position bitPosition
21 // Flip the bit at position (bitPosition - 1) to get the answer
22 int answer = num ^ (1 << (bitPosition - 1));
23 result.push_back(answer);
24 break;
25 }
26 }
27 }
28 }
29
30 return result;
31 }
32};
33
1/**
2 * Finds the minimum bitwise array for given numbers
3 * For each number x in nums, finds the smallest number a such that a | (a + 1) = x
4 * Returns -1 if no such number exists
5 * @param nums - Array of numbers to process
6 * @returns Array of minimum values or -1 if impossible
7 */
8function minBitwiseArray(nums: number[]): number[] {
9 const result: number[] = [];
10
11 for (const num of nums) {
12 // Special case: 2 has no valid solution
13 // There's no a where a | (a + 1) = 2
14 if (num === 2) {
15 result.push(-1);
16 } else {
17 // Find the first 0 bit from position 1 onwards
18 // This helps identify where we can form the pattern a | (a + 1) = num
19 for (let bitPosition = 1; bitPosition < 32; ++bitPosition) {
20 // Check if the bit at current position is 0
21 if (((num >> bitPosition) & 1) === 0) {
22 // Toggle the bit at position (bitPosition - 1) to get the answer
23 // This creates the smallest a such that a | (a + 1) equals num
24 const answer = num ^ (1 << (bitPosition - 1));
25 result.push(answer);
26 break;
27 }
28 }
29 }
30 }
31
32 return result;
33}
34
Time and Space Complexity
Time Complexity: O(n × log M)
The algorithm iterates through each element in the nums
array (length n
). For each element x
, it performs a bit-checking loop that runs from bit position 1 up to at most 31 (since we're checking 32-bit integers). The loop searches for the first bit position i
where the i
-th bit of x
is 0 (using x >> i & 1 ^ 1
). This bit-checking operation takes at most O(log M)
iterations, where M
is the maximum value in the array, as the number of bits needed to represent M
is proportional to log M
. Therefore, the overall time complexity is O(n × log M)
.
Space Complexity: O(1)
(excluding the output array)
The algorithm uses only a constant amount of extra space. It maintains a few variables (i
in the loop and temporary values during bit operations) that don't depend on the input size. The ans
array is used to store the results, but as stated in the reference, we ignore the space consumption of the answer array when analyzing space complexity. Therefore, the space complexity is O(1)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Bit Position Logic
A common mistake is confusing the relationship between the position of the rightmost 0 bit and which bit needs to be flipped. When we find a 0 bit at position i
, we need to flip the bit at position i-1
, not position i
itself.
Incorrect approach:
if ((num >> bit_position) & 1) == 0: answer = num ^ (1 << bit_position) # Wrong! Flips the 0 bit itself
Correct approach:
if ((num >> bit_position) & 1) == 0: answer = num ^ (1 << (bit_position - 1)) # Correct! Flips the bit before the 0
2. Starting Bit Search from Wrong Position
Another pitfall is starting the bit search from position 0 instead of position 1. Since we're looking for a OR (a+1)
, the least significant bit (position 0) will always be 1 in the result, so the rightmost 0 that matters must be at position 1 or higher.
Incorrect approach:
for bit_position in range(0, 32): # Wrong! Starts from position 0
Correct approach:
for bit_position in range(1, 32): # Correct! Starts from position 1
3. Forgetting to Handle Edge Cases
Not handling the special case where num = 2
(the only even prime) will lead to incorrect results or infinite loops, since no value a
satisfies a OR (a+1) = 2
.
Solution: Always check for even numbers first:
if num == 2: result.append(-1) continue
4. Not Breaking After Finding First Zero Bit
Continuing to search after finding the first 0 bit will overwrite the correct answer with incorrect values from higher bit positions.
Incorrect approach:
for bit_position in range(1, 32):
if ((num >> bit_position) & 1) == 0:
answer = num ^ (1 << (bit_position - 1))
result.append(answer)
# Missing break! Will append multiple values
Correct approach:
for bit_position in range(1, 32):
if ((num >> bit_position) & 1) == 0:
answer = num ^ (1 << (bit_position - 1))
result.append(answer)
break # Essential to stop after first 0 bit
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
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!