Taro Logo

Number of Steps to Reduce a Number in Binary Representation to One

Medium
Google logo
Google
1 view
Topics:
StringsBit Manipulation

Given the binary representation of an integer as a string s, return the number of steps to reduce it to 1 under the following rules:

  • If the current number is even, you have to divide it by 2.
  • If the current number is odd, you have to add 1 to it.

It is guaranteed that you can always reach one for all test cases.

For example:

  • s = "1101" should return 6 because "1101" corresponds to number 13 in their decimal representation. The steps are: 1) 13 is odd, add 1 and obtain 14. 2) 14 is even, divide by 2 and obtain 7. 3) 7 is odd, add 1 and obtain 8. 4) 8 is even, divide by 2 and obtain 4. 5) 4 is even, divide by 2 and obtain 2. 6) 2 is even, divide by 2 and obtain 1.
  • s = "10" should return 1 because "10" corresponds to number 2 in their decimal representation. The step is: 1) 2 is even, divide by 2 and obtain 1.
  • s = "1" should return 0.

Can you implement an efficient solution for this problem?

Solution


Naive Solution

A straightforward approach is to simulate the process as described in the problem statement. We can convert the binary string to an integer, then repeatedly apply the rules until we reach 1, counting the steps.

Code (Python)

def num_steps_naive(s: str) -> int:
    num = int(s, 2)
    steps = 0
    while num > 1:
        if num % 2 == 0:
            num //= 2
        else:
            num += 1
        steps += 1
    return steps

Time Complexity: O(N) where N is the value represented by the binary string s.

In the worst case, 's' represents a number close to 2^500. Each step either divides the number by 2 or adds 1. The number of steps is proportional to the value of the number.

Space Complexity: O(1)

We use a constant amount of extra space.

Optimal Solution

We can solve this problem without explicitly converting the binary string to an integer. Instead, we can directly operate on the binary string. We iterate from right to left. If we encounter a '0', we divide by 2 (equivalent to a right shift, so incrementing steps). If we encounter a '1', we add 1 (which may cause carries). The key is to track the carry.

Algorithm:

  1. Initialize steps = 0 and carry = 0.
  2. Iterate through the binary string s from right to left (excluding the leftmost bit).
  3. If the current bit is '0':
    • If carry is 0, increment steps by 1.
    • If carry is 1, increment steps by 2 (1 for flipping 0 to 1, and 1 for the next carry).
  4. If the current bit is '1':
    • If carry is 0, increment steps by 2 (1 for flipping 1 to 0, and 1 for the next carry).
    • If carry is 1, increment steps by 1 (1 for flipping 1 to 0; carry remains 1).
  5. After the loop, add 1 to steps to account for the final carry propagation to the leftmost bit.

Code (Python)

def num_steps(s: str) -> int:
    steps = 0
    carry = 0
    for i in range(len(s) - 1, 0, -1):
        if s[i] == '0':
            if carry == 0:
                steps += 1
            else:
                steps += 2
        else:
            if carry == 0:
                steps += 2
                carry = 1
            else:
                steps += 1
    steps += carry  # Account for the final carry propagation
    return steps

Edge Cases:

  • s = "1": return 0
  • s = "10": return 1
  • s = "11": return 2

Time Complexity: O(L) where L is the length of the binary string.

We iterate through the binary string once.

Space Complexity: O(1)

We use a constant amount of extra space for the steps and carry variables.