Construct the Minimum Bitwise Array I
EasyPrompt
You are given an array nums consisting of n prime integers.
You need to construct an array ans of length n, such that, for each index i, the bitwise OR of ans[i] and ans[i] + 1 is equal to nums[i], i.e. ans[i] OR (ans[i] + 1) == nums[i].
Additionally, you must minimize each value of ans[i] in the resulting array.
If it is not possible to find such a value for ans[i] that satisfies the condition, then set ans[i] = -1.
Example 1:
Input: nums = [2,3,5,7]
Output: [-1,1,4,3]
Explanation:
- For
i = 0, as there is no value forans[0]that satisfiesans[0] OR (ans[0] + 1) = 2, soans[0] = -1. - For
i = 1, the smallestans[1]that satisfiesans[1] OR (ans[1] + 1) = 3is1, because1 OR (1 + 1) = 3. - For
i = 2, the smallestans[2]that satisfiesans[2] OR (ans[2] + 1) = 5is4, because4 OR (4 + 1) = 5. - For
i = 3, the smallestans[3]that satisfiesans[3] OR (ans[3] + 1) = 7is3, because3 OR (3 + 1) = 7.
Example 2:
Input: nums = [11,13,31]
Output: [9,12,15]
Explanation:
- For
i = 0, the smallestans[0]that satisfiesans[0] OR (ans[0] + 1) = 11is9, because9 OR (9 + 1) = 11. - For
i = 1, the smallestans[1]that satisfiesans[1] OR (ans[1] + 1) = 13is12, because12 OR (12 + 1) = 13. - For
i = 2, the smallestans[2]that satisfiesans[2] OR (ans[2] + 1) = 31is15, because15 OR (15 + 1) = 31.
Constraints:
1 <= nums.length <= 1002 <= nums[i] <= 1000nums[i]is a prime number.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach uses a straightforward brute-force search. For each element num in the nums array, we iterate through all possible candidate values for ans[i] from 0 up to num - 1. For each candidate x, we check if it satisfies the condition x | (x + 1) == num. Since we are iterating from the smallest possible value upwards, the first candidate that satisfies the condition is guaranteed to be the minimum.
Algorithm
The core idea of this approach is to exhaustively search for the smallest possible value for ans[i].
- For each number
numin the input arraynums, we need to find the smallest non-negative integerxsuch thatx OR (x + 1) == num. - We know that
x OR (x + 1)will always be greater than or equal tox + 1. Therefore,num >= x + 1, which impliesx <= num - 1. - This gives us a finite search space for
x: from0tonum - 1. - We can iterate through this range. The first value of
xthat satisfies the conditionx OR (x + 1) == numwill be the smallest, because we are iterating in increasing order. - If the loop completes without finding any such
x, it means no solution exists for thatnum, and we should assign-1.
Walkthrough
The algorithm proceeds as follows:
- Initialize an integer array
answith the same length asnumsto store the results. - Iterate through the
numsarray fromi = 0ton-1. - For each
nums[i], start an inner loop with a variablexfrom0up tonums[i] - 1. - In the inner loop, compute
x | (x + 1)and check if it equalsnums[i]. - If the condition is met, we have found the smallest
x. We setans[i] = xand break out of the inner loop to proceed to the next number innums. - To handle cases where no solution is found, we can use a flag or initialize
ans[i]to-1before the inner loop. If the inner loop finishes without finding a solution,ans[i]will remain-1. - After iterating through all numbers in
nums, return theansarray.
class Solution { public int[] constructMinimizingBitwiseArray(int[] nums) { int n = nums.length; int[] ans = new int[n]; for (int i = 0; i < n; i++) { int num = nums[i]; int result = -1; // Search space for x is [0, num - 1] for (int x = 0; x < num; x++) { if ((x | (x + 1)) == num) { result = x; break; // Found the smallest x, no need to check further } } ans[i] = result; } return ans; }}Complexity
Time
O(N * M), where N is the number of elements in `nums` and M is the maximum value in `nums`. For each of the N numbers, we iterate up to M times. Given the constraints (N <= 100, M <= 1000), this is roughly 100 * 1000 = 10^5 operations, which is efficient enough.
Space
O(N) to store the output array `ans`. The auxiliary space complexity is O(1).
Trade-offs
Pros
Simple to understand and implement.
Guaranteed to find the correct minimum value if one exists.
Sufficiently fast for the given constraints.
Cons
The time complexity is dependent on the magnitude of the numbers in the input array, which can be inefficient if the numbers are very large.
It is a naive approach that doesn't leverage the underlying mathematical properties of the bitwise OR operation.
A highly efficient approach can be formulated by analyzing the bitwise properties of the equation x | (x + 1) = y. This analysis reveals a direct mathematical relationship between y (the value from nums) and the minimal x (the value for ans). This allows us to compute the result in constant time for each number, leading to a linear time solution overall.
Algorithm
This method is based on a mathematical derivation from the properties of bitwise operations.
- First, handle the special case where
numis the prime2. There is no non-negative integerxfor whichx | (x+1) = 2. So, ifnum = 2, the answer is-1. - For any odd prime
num, a solutionxcan be found. It can be proven that any solutionxmust be of the formx = num - 2^kfor some integerk >= 0. - To find the minimum
x, we must subtract the largest possible valid power of two,2^k, fromnum. - The correct value of
kis related to the binary representation ofnum + 1. Letpbe the number of trailing zeros innum + 1. The largest valid2^kwe can subtract is2^(p-1). - Thus, the smallest solution
xis given by the formula:x = num - (1 << (p - 1)), wherepis the number of trailing zeros innum + 1. - The number of trailing zeros can be efficiently calculated using built-in functions like
Integer.numberOfTrailingZeros().
Walkthrough
The core of this approach is a formula derived from the structure of x | (x+1).
Let y = nums[i]. We are solving x | (x+1) = y for the smallest x.
-
Case 1:
yis even. Sincenums[i]are prime, the only even case isy = 2. We can check that0|1=1,1|2=3. No non-negativexsatisfiesx | (x+1) = 2. So,ans[i] = -1. -
Case 2:
yis odd. For any oddy, a solution exists. The relationshipy = (x+1) + lsb(x+1) - 1holds, wherelsb(v)is the value of the least significant bit ofv(e.g.,lsb(12) = 4). This can be rearranged toy+1 = (x+1) + lsb(x+1). This equation implies that solutions forxmust be of the formy - 2^k.
To minimize x = y - 2^k, we need to maximize k. The largest k that yields a valid solution is determined by the number of trailing zeros in y+1.
Let p = Integer.numberOfTrailingZeros(y + 1). The formula for the minimal x is x = y - (1 << (p - 1)).
This single formula covers all odd y values:
- If
y = 5,y+1 = 6(binary110).p=1.x = 5 - (1 << 0) = 4. - If
y = 7,y+1 = 8(binary1000).p=3.x = 7 - (1 << 2) = 3. - If
y = 11,y+1 = 12(binary1100).p=2.x = 11 - (1 << 1) = 9.
class Solution { public int[] constructMinimizingBitwiseArray(int[] nums) { int n = nums.length; int[] ans = new int[n]; for (int i = 0; i < n; i++) { int num = nums[i]; // Since nums[i] is prime, the only even number is 2. if (num == 2) { ans[i] = -1; } else { // For any odd prime, a solution exists. // The smallest solution x is given by the formula: // x = num - 2^(p-1), where p is the number of trailing zeros in num + 1. int numPlusOne = num + 1; int p = Integer.numberOfTrailingZeros(numPlusOne); int powerOf2ToSubtract = 1 << (p - 1); ans[i] = num - powerOf2ToSubtract; } } return ans; }}Complexity
Time
O(N), where N is the number of elements in `nums`. Each number is processed in constant time using bitwise operations and a direct formula.
Space
O(N) to store the output array `ans`. The auxiliary space complexity is O(1).
Trade-offs
Pros
Extremely efficient with a linear time complexity.
Calculates the result directly without any searching or iteration.
Scales well even if the constraints on the input numbers were much larger.
Cons
The derivation of the formula is complex and not immediately obvious.
Requires a deeper understanding of bitwise operations and number properties.
Solutions
Solution
class Solution {public int[] minBitwiseArray(List<Integer> nums) { int n = nums.size(); int[] ans = new int[n]; for (int i = 0; i < n; ++i) { int x = nums.get(i); if (x == 2) { ans[i] = -1; } else { for (int j = 1; j < 32; ++j) { if ((x >> j & 1) == 0) { ans[i] = x ^ 1 << (j - 1); break; } } } } return ans; }}class Solution {public: vector<int> minBitwiseArray(vector<int> &nums) { vector<int> ans; for (int x : nums) { if (x == 2) { ans.push_back(-1); } else { for (int i = 1; i < 32; ++i) { if (x >> i & 1 ^ 1) { ans.push_back(x ^ 1 << (i - 1)); break; } } } } return ans; }};class Solution: def minBitwiseArray(self, nums: List[int]) -> List[int]: ans = [] for x in nums: if x == 2: ans . append(- 1) else: for i in range(1, 32): if x >> i & 1 ^ 1: ans . append(x ^ 1 << (i - 1)) break return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.