2 minute read

Problem Statement

problem-1404

Intuition

My initial thought is to repeatedly apply the rules given: if the number is even, divide by 2; if it’s odd, add 1. The process continues until the number is reduced to ‘1’. Since binary representation simplifies division by 2 (just shifting right) and addition of 1 (handling carry), these operations can be efficiently managed.

Approach

  1. Convert the binary string to an integer.
  2. Initialize a counter for steps.
  3. Loop until the number is 1:
    • If the number is even, divide it by 2.
    • If the number is odd, add 1.
    • Convert the result back to binary string for the next iteration.
  4. Increment the step counter each iteration.
  5. Return the total number of steps.

Complexity

  • Time complexity: The time complexity is (O(n)), where (n) is the number of bits in the binary string. Each operation (addition or division) reduces the number of bits, leading to a linear time complexity relative to the number of bits.

  • Space complexity: The space complexity is (O(1)) for the integer and step counter, not accounting for the space needed to store the binary string representation.

Code

class Solution:
    def numSteps(self, s: str) -> int:
        if s == '1':
            return 0
        steps = 0
        while s != '0b1':
            num = int(s, 2)
            if num % 2 == 0:
                num //= 2
            else:
                num += 1

            s = str(bin(num))
            steps += 1

        return steps

I will improve this code by handling the binary string operations directly without converting back and forth between binary string and integer. This avoids unnecessary conversions and improves efficiency.

class Solution:
    def numSteps(self, s: str) -> int:
        steps = 0
        while s != '1':
            if s[-1] == '0':
                s = s[:-1]
            else:
                s = bin(int(s, 2) + 1)[2:]
            steps += 1

        return steps

Editorial

Approach 1: Simulation

class Solution:
    def divide_by_two(self, s):
        s.pop()

    def add_one(self, s):
        i = len(s) - 1

        # Iterating while the character is 1 and changing to 0
        while i >= 0 and s[i] != "0":
            s[i] = "0"
            i -= 1

        if i < 0:
            s.insert(0, "1")
        else:
            s[i] = "1"

    def numSteps(self, s: str) -> int:
        s = list(s)
        operations = 0

        while len(s) > 1:
            N = len(s)

            if s[N - 1] == "0":
                self.divide_by_two(s)
            else:
                self.add_one(s)

            operations += 1

        return operations
  • Time: O(n^2)
  • Space: O(N)

Approach 2: Greedy

class Solution:
    def numSteps(self, s: str) -> int:
        N = len(s)

        operations = 0
        carry = 0
        for i in range(N - 1, 0, -1):
            digit = int(s[i]) + carry
            if digit % 2 == 1:
                operations += 2
                carry = 1
            else:
                operations += 1

        return operations + carry
  • Time: O(N)
  • Space: O(1)