Problem
You are given two integers num1
and num2
.
In one operation, you can choose integer i
in the range [0, 60]
and subtract 2i + num2
from num1
.
Return the integer denoting theminimum number of operations needed to make num1
equal to 0
.
If it is impossible to make num1
equal to 0
, return -1
.
Examples
Example 1
|
|
Example 2
|
|
Constraints
1 <= num1 <= 10^9
-109 <= num2 <= 10^9
Solution
Method 1 – Bit Manipulation & Enumeration
Intuition
After a bit of playing around, it seems hard to find an explicit formula for the answer. As with many computer science problems, we can instead try to search over the answer space, trading runtime for ease of implementation.
To make num1
equal to zero, we perform a series of operations. We start by subtracting num2
from num1
, and then subtract powers of two (2^k1
, 2^k2
, and so on) from the result.
When we rearrange the equation, we get:
`num1 - k * num2 - (2^k1 + 2^k2 + ...) == 0`
This equation states that num1
can be expressed as the sum of k
times num2
and the sum of powers of two.
The goal is to find the values of k
and the powers of two that make num1
equal to zero. By subtracting num2
and powers of two from num1
in each step, we aim to reduce the remaining value to zero.
Therefore, the problem becomes finding the minimum combination of k
and the powers of two needed to reach zero.
Why checking bits and steps
Checking the number of set bits (bits
): The count of set bits in the diff
value represents the number of powers of two needed to construct the remaining value after subtracting num2 * steps
from num1
. Recall that each power of two corresponds to an operation. If the count of set bits is less than or equal to the current step, it means that we have enough powers of two to perform the required operations within the given step count.
Checking if the step falls within the range of diff
: The range of diff
represents the remaining value after subtracting num2 * steps
from num1
. If the current step falls within this range, it indicates that we can continuously subtract powers of two from the remaining value until it becomes zero. By ensuring the step falls within the range, we confirm that the remaining value can be reduced to zero using the given number of steps.
By checking both conditions, we ensure that we have enough powers of two and a valid range to perform the necessary operations and make num1
equal to zero. If both conditions are met, the function returns the minimum number of steps required. Otherwise, it continues to the next iteration to check for other possible step counts.
In summary, the conditions of checking the number of set bits and the range of diff
validate the feasibility of making num1
zero within the given step count and help in determining the minimum number of steps required.
Approach
target := num1 - k * num2 = 2^i1 + 2^i2 + … + 2^ik
We can test whether or not k
operations is sufficient for some given k
.
If k
operations are used, then:
|
|
for some i1
, i2
, …, ik
in [0, 60]
.
Rearranging, this gives:
|
|
Observe that we can construct any positive integer x
with at least x.bit_count()
powers of two and at most x
powers of two. This is because we can start with the powers of two that make up the bits of x
, then continue to split apart larger powers of two into smaller powers of two until we are left with just 1’s. For instance, 5 = 4 + 1 = (2 + 2) + 1 = 2 + (1 + 1) + 1 = (1 + 1) + 1 + 1 + 1
. Thus, we must have target.bit_count() <= k <= target
.
Using the above algorithm to determine whether a certain number of operations is valid, we can do a linear search through all possible number of operations in [0,60]
and take the minimum valid answer.
Why the answer is bounded from above by 60
target < 0, target.bit_count() > k, or k > target.
Assume there is no valid answer for k <= 60
. Then, at least one of the following hold for k = 60
:
|
|
(2) is impossible since target := num1 - k * num2
is bounded from above by the input constraints.
If (1) is true, then num1 - k * num2 < 0
implies num2 > 0
, meaning target
is strictly decreasing while k
is strictly increasing. If we have not found a solution by this point, this implies there is no solution past 60.
If (3) is true, k > num1 - k * num2
implies k * (num2 + 1) > num1
, meaning either num2 = 0
, in which case k = num1.bit_count()
will have previously been a valid answer, or num2 > 0
. Again, target
is strictly decreasing while k
is strictly increasing; there is no solution.
In all cases, there is either a contradiction or no solution; k
is bounded from above. As a matter of fact, there can be a tighter bound on k
as long as the argument for (2) holds.
Code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Complexity
- ⏰ Time complexity:
O(60) = O(1)
— We check up to 60 possible values for k, and for each, count bits in a number. - 🧺 Space complexity:
O(1)
— Only a few variables are used, no extra space proportional to input size.