Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

991. Broken Calculator - Leetcode Solution

Problem Description

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:

  • Multiply the current number by 2 (i.e., x = x * 2).
  • Subtract 1 from the current number (i.e., 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:

  • 1 ≤ startValue, target ≤ 109

Thought Process

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:

  • If we can multiply by 2 going forward, we can divide by 2 going backward (when the number is even).
  • If we can subtract 1 going forward, we can add 1 going backward.

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.

Solution Approach

Let's break down the optimized approach step by step:

  1. Work Backwards: Start from target and try to reduce it to startValue using the reverse operations:
    • If target is even, divide it by 2 (since this is the reverse of multiplying by 2).
    • If target is odd, add 1 (since this is the reverse of subtracting 1).
  2. Repeat Until Target ≤ StartValue: Keep applying these reverse operations until target becomes less than or equal to startValue.
  3. Handle Remaining Difference: If 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.
  4. Count Operations: For each step taken in the process, increment a counter to represent the total number of operations.

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 Walkthrough

Example: startValue = 5, target = 8

  1. Target (8) is greater than StartValue (5):
    • 8 is even, so divide by 2: 8 → 4 (1 operation)
  2. Now target is 4, which is less than startValue (5):
    • We need to add (5 - 4) = 1 operation (subtract 1 in the forward direction)
  3. Total operations: 1 (divide by 2) + 1 (subtract 1) = 2
  4. Sequence:
    • 5 → 4 (subtract 1)
    • 4 → 8 (multiply by 2)
    or
    • 5 → 10 (multiply by 2), 10 → 9 (subtract 1), 9 → 8 (subtract 1): 3 steps (not optimal)
    The optimized way (working backwards) finds the minimum steps.

Time and Space Complexity

Brute-force approach:

  • Time Complexity: Exponential, since there are multiple choices at each step and the number of states grows rapidly.
  • Space Complexity: Also exponential, due to the call stack or queue used in recursion or BFS.
Optimized approach:
  • Time Complexity: O(\log{target}) because we halve the target at each step (when possible), leading to logarithmic steps.
  • Space Complexity: O(1) since we only use a few variables for counters and current values.

Summary

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.

Code Implementation

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);
};