LeetCode 1404 - Number of Steps to Reduce a Number in Binary Representation to One

The problem gives us a binary number represented as a string s. Our task is to determine how many operations are require

LeetCode Problem 1404

Difficulty: 🟡 Medium
Topics: String, Bit Manipulation, Simulation

Solution

Problem Understanding

The problem gives us a binary number represented as a string s. Our task is to determine how many operations are required to reduce this number to exactly 1.

The allowed operations depend on whether the current value is even or odd:

  • If the number is even, divide it by 2
  • If the number is odd, add 1

Because the input is given in binary form, we should think carefully about how these operations behave at the bit level.

For example, the binary string "1101" represents decimal 13.

  • 13 is odd, so we add 114
  • 14 is even, so divide by 27
  • Continue until the value becomes 1

The answer is simply the number of operations performed.

The constraints are important:

  • s.length <= 500

A 500 bit binary number is far larger than what standard integer types can store safely in many languages. Converting the entire string into an integer and repeatedly simulating operations may work in Python because Python integers are arbitrary precision, but it is not ideal algorithmically and becomes inconvenient in languages like Go.

The constraints strongly suggest that we should process the binary string directly instead of repeatedly converting large values.

Several edge cases are important:

  • "1" already equals the target, so the answer is 0
  • Strings with many carry propagations such as "111111" can expose bugs in binary addition logic
  • Powers of two such as "100000" should repeatedly divide cleanly
  • Very large inputs require an efficient linear solution

The problem guarantees:

  • The string always starts with '1'
  • The string contains only '0' and '1'
  • It is always possible to reach 1

This means we never need to handle invalid binary numbers or impossible cases.

Approaches

Brute Force Approach

The most direct approach is to repeatedly simulate the operations on the actual number.

We could:

  1. Convert the binary string into an integer
  2. While the value is not 1:
  • If even, divide by 2
  • If odd, add 1
  1. Count the operations

This approach is conceptually simple and clearly correct because it follows the problem statement exactly.

However, there are practical issues:

  • The binary string can contain up to 500 bits
  • Standard integer types cannot hold such large values
  • Repeated big integer arithmetic can become expensive

In Python, arbitrary precision integers make this technically feasible, but it still performs repeated large arithmetic operations. In languages without built in big integers, implementation becomes much more complicated.

Optimal Approach

The key insight is that we do not actually need the numeric value itself. We only need to understand how binary operations affect the bits.

Observe the rules in binary:

  • Dividing by 2 simply removes the last bit
  • Odd numbers always end with '1'
  • Adding 1 to an odd binary number creates carry propagation

Instead of simulating the entire number, we process the string from right to left while tracking whether a carry exists.

For each bit:

  • If the effective bit is even (0), one operation is needed, divide by 2

  • If the effective bit is odd (1), two operations are needed:

  • add 1

  • divide by 2

The carry determines whether the current bit effectively changes value.

This produces a clean linear time solution.

Approach Time Complexity Space Complexity Notes
Brute Force O(n²) O(n) Repeated big integer operations on very large binary numbers
Optimal O(n) O(1) Single pass from right to left using carry simulation

Algorithm Walkthrough

Step 1: Handle the simplest case

If the input is "1", the number is already reduced to one, so return 0.

Step 2: Initialize variables

We maintain:

  • steps, the total number of operations
  • carry, representing whether a previous addition created a carry into the current bit

Initially:

  • steps = 0
  • carry = 0

Step 3: Traverse from right to left

We iterate from the least significant bit toward the most significant bit, excluding the first character.

We exclude the first bit because the process stops once we reach the leading 1.

Step 4: Compute the effective current bit

At each position:

  • Convert the character to an integer bit
  • Add the carry

So:

effective_bit = current_bit + carry

Possible values:

  • 0
  • 1
  • 2

Step 5: Handle even values

If the effective bit is even:

  • We only need one operation, divide by 2

This happens when:

  • 0
  • 2

So:

steps += 1

The carry remains unchanged.

Step 6: Handle odd values

If the effective bit is odd:

  • First add 1
  • Then divide by 2

So we need two operations:

steps += 2

Adding 1 creates a carry for future bits:

carry = 1

Step 7: Process the most significant carry

After processing all lower bits:

  • If a carry still exists, one extra operation is required

For example:

111 + 1 = 1000

This adds an extra division step.

So:

steps += carry

Why it works

The algorithm works because every operation affects only the least significant bits.

  • Even numbers always end in 0, so dividing by 2 removes one bit
  • Odd numbers always end in 1, so adding 1 transforms trailing ones into zeros and propagates a carry

By tracking carry propagation explicitly, we simulate the exact effect of binary addition without constructing large integers. Each bit is processed exactly once, and every required operation is counted precisely.

Python Solution

class Solution:
    def numSteps(self, s: str) -> int:
        if s == "1":
            return 0

        steps = 0
        carry = 0

        for i in range(len(s) - 1, 0, -1):
            current_bit = int(s[i])
            effective_value = current_bit + carry

            if effective_value % 2 == 0:
                steps += 1
            else:
                steps += 2
                carry = 1

        steps += carry

        return steps

The implementation begins by checking whether the input is already "1". This prevents unnecessary processing and correctly handles the smallest possible input.

The algorithm then initializes two variables:

  • steps tracks the total number of operations
  • carry tracks whether a previous addition propagated into the current position

The loop iterates from the last index down to index 1, processing bits from right to left while excluding the leading bit.

At each iteration:

  • The current binary character is converted into an integer
  • The carry is added to determine the effective value

If the effective value is even, only one divide by 2 operation is required.

If the effective value is odd, two operations are required:

  1. Add 1
  2. Divide by 2

In that case, the carry becomes 1.

Finally, after all bits are processed, any remaining carry contributes one additional operation.

Go Solution

func numSteps(s string) int {
    if s == "1" {
        return 0
    }

    steps := 0
    carry := 0

    for i := len(s) - 1; i > 0; i-- {
        currentBit := int(s[i] - '0')
        effectiveValue := currentBit + carry

        if effectiveValue%2 == 0 {
            steps += 1
        } else {
            steps += 2
            carry = 1
        }
    }

    steps += carry

    return steps
}

The Go implementation follows the same logic as the Python version.

One small language specific detail is converting characters into integers:

currentBit := int(s[i] - '0')

Go strings are byte slices, so subtracting '0' converts the ASCII digit into its numeric value.

No large integer arithmetic is used, so there are no overflow concerns even for 500 bit inputs.

Worked Examples

Example 1

Input:

s = "1101"
Iteration Bit Carry Before Effective Value Operations Added Carry After Total Steps
Start - 0 - - 0 0
i = 3 1 0 1 +2 1 2
i = 2 0 1 1 +2 1 4
i = 1 1 1 2 +1 1 5
Final Carry - 1 - +1 - 6

Final answer:

6

Example 2

Input:

s = "10"
Iteration Bit Carry Before Effective Value Operations Added Carry After Total Steps
Start - 0 - - 0 0
i = 1 0 0 0 +1 0 1

Final answer:

1

Example 3

Input:

s = "1"

The number is already 1.

No operations are needed.

Final answer:

0

Complexity Analysis

Measure Complexity Explanation
Time O(n) Each bit is processed exactly once
Space O(1) Only a few variables are used

The algorithm performs a single traversal of the binary string from right to left. Every iteration executes constant time operations, so the total runtime grows linearly with the length of the input.

The space usage is constant because no auxiliary data structures proportional to input size are allocated.

Test Cases

solution = Solution()

assert solution.numSteps("1") == 0          # already one
assert solution.numSteps("10") == 1         # single division
assert solution.numSteps("11") == 3         # add then divide twice
assert solution.numSteps("1101") == 6       # provided example
assert solution.numSteps("111") == 4        # carry propagation
assert solution.numSteps("1010") == 6       # alternating bits
assert solution.numSteps("1000") == 3       # power of two
assert solution.numSteps("1111") == 5       # multiple carries
assert solution.numSteps("101111") == 8     # mixed pattern
assert solution.numSteps("1000000000") == 9 # large power of two
Test Why
"1" Validates immediate termination
"10" Smallest nontrivial even number
"11" Tests odd handling and carry
"1101" Validates official example
"111" Tests repeated carry propagation
"1010" Tests alternating parity
"1000" Tests repeated division only
"1111" Tests long carry chains
"101111" Mixed pattern stress case
"1000000000" Large power of two

Edge Cases

Edge Case 1: Input Already Equal to One

The input "1" is special because no operations are needed. A careless implementation might still enter the processing loop and incorrectly add operations.

The solution explicitly checks for this case at the beginning and immediately returns 0.

Edge Case 2: Long Carry Propagation

Inputs like "111111" are tricky because adding 1 causes carries to propagate through many bits.

For example:

111111 + 1 = 1000000

A naive bit simulation can easily mishandle these cascading carries.

The implementation handles this cleanly with the carry variable, which propagates automatically through the traversal.

Edge Case 3: Powers of Two

Inputs such as "100000" are already even after every operation.

The correct behavior is repeated division by 2 until only "1" remains.

The algorithm handles this naturally because every processed bit evaluates to even, contributing exactly one operation per bit.

Edge Case 4: Very Large Binary Strings

The input length can reach 500 bits, which exceeds standard integer ranges.

Solutions that rely on fixed width integer conversion can overflow.

This implementation never converts the full binary string into an integer. It processes characters directly, so it safely handles arbitrarily large binary representations within the problem constraints.