Facebook Pixel

991. Broken Calculator

Problem Description

You have a broken calculator that initially displays the integer startValue. The calculator can only perform two operations:

  1. Multiply by 2: Multiply the current number on the display by 2
  2. Subtract 1: Subtract 1 from the current number on the display

Given two integers startValue and target, you need to find the minimum number of operations required to transform the initial value startValue into the target value.

For example, if startValue = 2 and target = 3, you could:

  • Multiply 2 by 2 to get 4 (1 operation)
  • Subtract 1 to get 3 (1 operation)
  • Total: 2 operations

The goal is to determine the optimal sequence of these two operations that will get you from startValue to target using the fewest number of steps possible.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is to think about this problem in reverse. Instead of going from startValue to target, we work backwards from target to startValue.

Why does this help? Consider the two operations we can perform forward:

  • Multiply by 2
  • Subtract 1

When we reverse these operations, they become:

  • Divide by 2 (reverse of multiply by 2)
  • Add 1 (reverse of subtract 1)

Working backwards is more efficient because:

  1. When target is larger than startValue, going forward would require many multiply operations, but we might overshoot and need to subtract. It's hard to predict the optimal path.

  2. Working backwards gives us clear rules:

    • If target is even, we should divide by 2 (since this was a multiply operation going forward)
    • If target is odd, we can't divide by 2, so we must add 1 first to make it even

This greedy approach works because dividing by 2 reduces the number much faster than adding 1. So whenever we can divide (when the number is even), we should do it.

The process continues until target becomes less than or equal to startValue. At that point, we can only use subtraction operations going forward (since multiplication would increase the value). The remaining operations needed are simply startValue - target.

For example, with startValue = 2 and target = 3:

  • Start with 3 (odd), add 1 → 4 (1 operation)
  • 4 is even, divide by 2 → 2 (1 operation)
  • Now 2 equals startValue, so we're done with 2 operations

Learn more about Greedy and Math patterns.

Solution Approach

The implementation uses a reverse calculation method, working backwards from target to startValue.

Here's how the algorithm works step by step:

  1. Initialize a counter: Start with ans = 0 to count the number of operations.

  2. Main loop: While startValue < target, we perform reverse operations on target:

    • Check if target is odd: We use bitwise AND (target & 1) to check if the least significant bit is 1, which indicates an odd number
    • If odd: Add 1 to target (target += 1). This reverses a subtract operation
    • If even: Divide target by 2 using right shift (target >>= 1). This reverses a multiply operation
    • Increment the operation counter (ans += 1) for each iteration
  3. Final adjustment: Once target <= startValue, we can only reach target from startValue through subtraction operations. Add startValue - target to the operation count.

  4. Return the result: The total number of operations is stored in ans.

The algorithm efficiently uses:

  • Bitwise operations for performance: target & 1 checks oddness, target >>= 1 divides by 2
  • Greedy approach: Always choosing division when possible (for even numbers) minimizes operations since division reduces the value faster than addition
  • Simple arithmetic: The final step handles any remaining difference with direct subtraction count

Time Complexity: O(log target) - In the worst case, we divide target by 2 repeatedly until it's less than startValue

Space Complexity: O(1) - We only use a constant amount of extra space for the counter variable

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's walk through the solution with startValue = 5 and target = 8.

Working backwards from target to startValue:

Initial state: ans = 0, we need to transform target = 8 to reach startValue = 5 or below.

Step 1: Check if 5 < 8? Yes, so we continue.

  • Is 8 odd? Check 8 & 1 = 0, so it's even.
  • Since it's even, divide by 2: 8 >> 1 = 4
  • Increment counter: ans = 1
  • Current state: target = 4, ans = 1

Step 2: Check if 5 < 4? No, so we exit the loop.

Step 3: Final adjustment:

  • Since target = 4 is now less than startValue = 5, we need startValue - target = 5 - 4 = 1 more operation
  • Add to counter: ans = 1 + 1 = 2

Result: Minimum operations needed = 2

Verification (forward direction):

  • Start with 5
  • Operation 1: Multiply by 2 → 10
  • Operation 2: Subtract 1 → 9
  • Operation 3: Subtract 1 → 8
  • Wait, that's 3 operations!

Let me recalculate:

  • Start with 5
  • Operation 1: Subtract 1 → 4
  • Operation 2: Multiply by 2 → 8
  • Total: 2 operations ✓

The algorithm correctly found that we need to subtract first to get to 4, then multiply by 2 to reach 8, using exactly 2 operations.

Solution Implementation

1class Solution:
2    def brokenCalc(self, startValue: int, target: int) -> int:
3        # Initialize operation counter
4        operations = 0
5      
6        # Work backwards from target to startValue
7        # While target is greater than startValue, reduce target
8        while startValue < target:
9            # Check if target is odd using bitwise AND
10            if target & 1:  # Equivalent to: if target % 2 == 1
11                # If target is odd, we must have reached it by subtracting 1
12                # So add 1 to reverse that operation
13                target += 1
14            else:
15                # If target is even, we could have reached it by multiplying by 2
16                # So divide by 2 (using right shift for efficiency)
17                target >>= 1  # Equivalent to: target //= 2
18          
19            # Increment operation count
20            operations += 1
21      
22        # After the loop, target <= startValue
23        # We need (startValue - target) subtractions to reach target
24        operations += startValue - target
25      
26        return operations
27
1class Solution {
2    public int brokenCalc(int startValue, int target) {
3        // Count the minimum number of operations needed
4        int operationCount = 0;
5      
6        // Work backwards from target to startValue
7        // We reverse the operations: multiply by 2 becomes divide by 2,
8        // and subtract 1 becomes add 1
9        while (startValue < target) {
10            // Check if target is odd using bitwise AND
11            if ((target & 1) == 1) {
12                // If target is odd, we add 1 (reverse of subtract 1)
13                target++;
14            } else {
15                // If target is even, we divide by 2 (reverse of multiply by 2)
16                // Using right shift for division by 2
17                target >>= 1;
18            }
19            // Increment operation count for each step
20            operationCount++;
21        }
22      
23        // If startValue >= target after the loop, we need additional subtract operations
24        // Add the difference to account for these remaining operations
25        operationCount += startValue - target;
26      
27        return operationCount;
28    }
29}
30
1class Solution {
2public:
3    int brokenCalc(int startValue, int target) {
4        // Count the number of operations needed
5        int operationCount = 0;
6      
7        // Work backwards from target to startValue
8        // If we were going forward: multiply by 2 or subtract 1
9        // Going backward: divide by 2 (if even) or add 1 (if odd)
10        while (startValue < target) {
11            // Check if target is odd using bitwise AND
12            if (target & 1) {
13                // If target is odd, we must have arrived here by subtracting 1
14                // So going backward means adding 1
15                target++;
16            } else {
17                // If target is even, we could have arrived here by multiplying by 2
18                // So going backward means dividing by 2 (right shift by 1)
19                target >>= 1;
20            }
21            // Increment operation counter
22            ++operationCount;
23        }
24      
25        // If startValue >= target, we can only subtract to reach target
26        // Add the remaining difference to the operation count
27        operationCount += startValue - target;
28      
29        return operationCount;
30    }
31};
32
1/**
2 * Calculates the minimum number of operations to transform startValue to target
3 * using two operations: multiply by 2 or subtract 1
4 * We work backwards from target to startValue for efficiency
5 */
6function brokenCalc(startValue: number, target: number): number {
7    let operationCount = 0;
8  
9    // Work backwards from target to startValue
10    // Continue while startValue is less than target
11    for (; startValue < target; operationCount++) {
12        // Check if target is odd using bitwise AND
13        if (target & 1) {
14            // If target is odd, we can only reach it by subtracting 1
15            // So we increment target (reverse of subtract 1)
16            target++;
17        } else {
18            // If target is even, we can reach it by multiplying by 2
19            // So we divide target by 2 (reverse of multiply by 2)
20            target >>= 1; // Right shift by 1 is equivalent to dividing by 2
21        }
22    }
23  
24    // If startValue >= target, we can only subtract 1 repeatedly
25    // Add the difference to the operation count
26    operationCount += startValue - target;
27  
28    return operationCount;
29}
30

Time and Space Complexity

The time complexity is O(log target). The algorithm works backwards from target to startValue. In each iteration of the while loop, when startValue < target, we either add 1 to target (if it's odd) or divide target by 2 (if it's even). Since division by 2 happens for even numbers, the value of target decreases exponentially, similar to binary search. The maximum number of iterations is proportional to the number of bits in target, which is log₂(target). After the loop, we perform a constant time operation startValue - target, so the overall time complexity remains O(log target).

The space complexity is O(1). The algorithm only uses a constant amount of extra space for the variables ans, startValue, and target. No additional data structures that grow with input size are used, and there's no recursion that would consume stack space.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Attempting Forward Simulation Instead of Backward

The most common mistake is trying to solve this problem by working forward from startValue to target. This approach leads to a complex branching problem where at each step you must decide whether to multiply by 2 or subtract 1, resulting in an exponential search space.

Why it fails: When working forward, you don't know which operation to choose at each step. For example, starting from 2 to reach 3, should you multiply first (2→4) or subtract first (2→1)? This creates a tree of possibilities that's difficult to optimize.

Solution: Always work backward from target to startValue. The reverse operations are deterministic:

  • If the current number is odd, you must add 1 (reversing a subtraction)
  • If the current number is even, divide by 2 (reversing a multiplication)

2. Incorrect Handling of Edge Cases Where startValue >= target

Some implementations forget to handle cases where startValue is already greater than or equal to target.

Example pitfall code:

def brokenCalc(self, startValue: int, target: int) -> int:
    operations = 0
    while target > startValue:  # Wrong condition!
        if target & 1:
            target += 1
        else:
            target >>= 1
        operations += 1
    return operations  # Missing the final adjustment!

Solution: The correct approach uses while startValue < target and then adds startValue - target after the loop to handle any remaining difference through subtraction operations.

3. Using Inefficient Operations

Using modulo operator (%) and integer division (//) instead of bitwise operations can impact performance in competitive programming scenarios.

Less efficient:

if target % 2 == 1:  # Modulo operation
    target += 1
else:
    target = target // 2  # Integer division

More efficient:

if target & 1:  # Bitwise AND
    target += 1
else:
    target >>= 1  # Right shift

4. Overthinking the Greedy Choice

Some may question why dividing by 2 (when working backward) is always optimal for even numbers. They might try to implement complex logic to decide between operations.

Why the greedy approach works: When working backward:

  • Dividing by 2 reduces the number faster than adding 1
  • If we need to eventually reach a smaller startValue, reducing target quickly minimizes total operations
  • The mathematical proof: any sequence of operations can be rearranged to group all multiplications before subtractions without increasing the operation count
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which type of traversal does breadth first search do?


Recommended Readings

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

Load More