The Broken Calculator problem on LeetCode asks you to compute the minimum number of operations needed to transform a starting value startValue
into a target value target
using only two operations:
x = x * 2
).x = x - 1
).
You can use these operations in any order and as many times as needed. Your task is to return the minimum number of operations needed to transform startValue
into target
.
Constraints:
startValue
, target
≤ 109
At first glance, it’s tempting to simulate every possible sequence of operations from startValue
to target
. However, this brute-force approach is inefficient, especially for large numbers, because the number of possible sequences grows exponentially.
Instead, we can reverse our thinking: rather than moving from startValue
up to target
, what if we start from target
and work backwards to startValue
? This is possible because:
This reversal allows us to minimize the number of operations by halving the target whenever possible, which is generally more efficient than subtracting 1 repeatedly.
Let's break down the optimized approach step by step:
target
and try to reduce it to startValue
using the reverse operations:
target
is even, divide it by 2 (since this is the reverse of multiplying by 2).target
is odd, add 1 (since this is the reverse of subtracting 1).target
becomes less than or equal to startValue
.
target
is now less than startValue
, we can only use the subtract 1 operation (forward) to reach target
from startValue
. This requires startValue - target
additional steps.
This method is efficient because dividing by 2 reduces the number much faster than subtracting 1 repeatedly, and we only subtract when necessary (i.e., when the number is odd).
Example: startValue = 5
, target = 8
Brute-force approach:
O(\log{target})
because we halve the target at each step (when possible), leading to logarithmic steps.O(1)
since we only use a few variables for counters and current values.The Broken Calculator problem demonstrates the power of working backwards from the target to the start, transforming a potentially exponential brute-force search into an efficient logarithmic algorithm. By always dividing by 2 when possible and only subtracting when necessary, we minimize the number of steps. This approach is both elegant and practical, making it suitable for very large input values.
class Solution:
def brokenCalc(self, startValue: int, target: int) -> int:
operations = 0
while target > startValue:
if target % 2 == 0:
target //= 2
else:
target += 1
operations += 1
return operations + (startValue - target)
class Solution {
public:
int brokenCalc(int startValue, int target) {
int operations = 0;
while (target > startValue) {
if (target % 2 == 0) {
target /= 2;
} else {
target += 1;
}
operations++;
}
return operations + (startValue - target);
}
};
class Solution {
public int brokenCalc(int startValue, int target) {
int operations = 0;
while (target > startValue) {
if (target % 2 == 0) {
target /= 2;
} else {
target += 1;
}
operations++;
}
return operations + (startValue - target);
}
}
var brokenCalc = function(startValue, target) {
let operations = 0;
while (target > startValue) {
if (target % 2 === 0) {
target = target / 2;
} else {
target = target + 1;
}
operations++;
}
return operations + (startValue - target);
};