Facebook Pixel

1342. Number of Steps to Reduce a Number to Zero

EasyBit ManipulationMath
Leetcode Link

Problem Description

You are given a positive integer num. Your task is to count how many steps it takes to reduce this number to zero by following these rules:

  • If the current number is even, divide it by 2
  • If the current number is odd, subtract 1 from it

Each operation (division by 2 or subtraction of 1) counts as one step. Continue applying these operations until the number becomes 0, then return the total number of steps taken.

For example, if num = 14:

  • Step 1: 14 is even, divide by 2 to get 7
  • Step 2: 7 is odd, subtract 1 to get 6
  • Step 3: 6 is even, divide by 2 to get 3
  • Step 4: 3 is odd, subtract 1 to get 2
  • Step 5: 2 is even, divide by 2 to get 1
  • Step 6: 1 is odd, subtract 1 to get 0

The answer would be 6 steps.

The solution uses a while loop that continues until num becomes 0. In each iteration, it checks if the number is odd using the bitwise AND operation num & 1 (which returns 1 if the last bit is 1, indicating an odd number). If odd, it subtracts 1; if even, it performs a right shift num >>= 1 which is equivalent to dividing by 2. A counter ans tracks the total number of steps.

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

Intuition

The problem asks us to repeatedly apply two operations based on whether the number is even or odd. This naturally suggests a simulation approach where we simply follow the given rules until we reach zero.

The key insight is that we need to keep track of two things: the current value of the number and the count of operations performed. Since we don't know in advance how many steps it will take, a while loop that continues until num becomes 0 is the natural choice.

For checking whether a number is even or odd, we have multiple options. The traditional approach would be to use the modulo operator num % 2. However, we can optimize this using bitwise operations. When we look at the binary representation of any number, the least significant bit (rightmost bit) determines if it's odd or even - if this bit is 1, the number is odd; if it's 0, the number is even. We can check this using num & 1, which performs a bitwise AND with 1 and returns 1 for odd numbers and 0 for even numbers.

Similarly, for dividing by 2, instead of using regular division num // 2, we can use the right shift operator num >> 1. Shifting bits to the right by one position is equivalent to integer division by 2, but it's a more efficient operation at the hardware level.

The algorithm is straightforward: keep a counter starting at 0, and in each iteration, check if the number is odd or even, perform the appropriate operation, increment the counter, and continue until the number reaches 0. The counter at the end gives us the total number of steps required.

Learn more about Math patterns.

Solution Approach

The implementation follows a straightforward simulation approach using a while loop. Let's walk through the algorithm step by step:

  1. Initialize a counter: Start with ans = 0 to keep track of the number of steps taken.

  2. Loop until zero: Use while num: which continues as long as num is not zero. In Python, any non-zero integer evaluates to True, so the loop runs until num becomes 0.

  3. Check odd or even: Inside the loop, use the bitwise AND operation num & 1 to determine if the number is odd:

    • num & 1 returns 1 if the least significant bit is 1 (odd number)
    • num & 1 returns 0 if the least significant bit is 0 (even number)
  4. Perform the appropriate operation:

    • If num & 1 is true (odd): Subtract 1 from the number using num -= 1
    • If num & 1 is false (even): Divide by 2 using the right shift operator num >>= 1
  5. Increment the counter: After each operation, increment ans += 1 to count this step.

  6. Return the result: Once the loop exits (when num becomes 0), return ans which contains the total number of steps.

The bitwise operations used here are optimizations:

  • num & 1 is more efficient than num % 2 for checking odd/even
  • num >> 1 is more efficient than num // 2 for division by 2

The time complexity is O(log n) because in the worst case (when we have the maximum number of divisions by 2), we're essentially counting the number of bits in the binary representation of the number. The space complexity is O(1) as 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 trace through the algorithm with num = 11:

Initial State: num = 11, ans = 0

Step 1:

  • Check: 11 & 1 = 1 (odd, because binary 1011 ends in 1)
  • Operation: num = 11 - 1 = 10
  • Update counter: ans = 1

Step 2:

  • Check: 10 & 1 = 0 (even, because binary 1010 ends in 0)
  • Operation: num = 10 >> 1 = 5 (shift 1010 right to get 0101)
  • Update counter: ans = 2

Step 3:

  • Check: 5 & 1 = 1 (odd, because binary 0101 ends in 1)
  • Operation: num = 5 - 1 = 4
  • Update counter: ans = 3

Step 4:

  • Check: 4 & 1 = 0 (even, because binary 0100 ends in 0)
  • Operation: num = 4 >> 1 = 2 (shift 0100 right to get 0010)
  • Update counter: ans = 4

Step 5:

  • Check: 2 & 1 = 0 (even, because binary 0010 ends in 0)
  • Operation: num = 2 >> 1 = 1 (shift 0010 right to get 0001)
  • Update counter: ans = 5

Step 6:

  • Check: 1 & 1 = 1 (odd, because binary 0001 ends in 1)
  • Operation: num = 1 - 1 = 0
  • Update counter: ans = 6

Loop exits because num = 0

Return: ans = 6

The sequence of operations was: 11 → 10 → 5 → 4 → 2 → 1 → 0, taking 6 steps total.

Solution Implementation

1class Solution:
2    def numberOfSteps(self, num: int) -> int:
3        """
4        Count the number of steps to reduce a number to zero.
5        For odd numbers: subtract 1
6        For even numbers: divide by 2
7      
8        Args:
9            num: A non-negative integer to be reduced to zero
10          
11        Returns:
12            The number of steps required to reduce num to zero
13        """
14        step_count = 0
15      
16        # Continue until the number becomes zero
17        while num > 0:
18            # Check if the number is odd using bitwise AND
19            if num & 1:  # Odd number (last bit is 1)
20                num -= 1
21            else:  # Even number (last bit is 0)
22                num >>= 1  # Right shift by 1 (equivalent to dividing by 2)
23          
24            # Increment the step counter
25            step_count += 1
26      
27        return step_count
28
1class Solution {
2  
3    /**
4     * Counts the number of steps to reduce a number to zero.
5     * In each step:
6     * - If the number is even, divide it by 2
7     * - If the number is odd, subtract 1 from it
8     * 
9     * @param num The input number to be reduced to zero
10     * @return The number of steps required to reduce num to zero
11     */
12    public int numberOfSteps(int num) {
13        int stepCount = 0;
14      
15        // Continue until the number becomes zero
16        while (num != 0) {
17            // Check if the number is odd using bitwise AND with 1
18            // If odd (last bit is 1), subtract 1; if even, divide by 2 using right shift
19            if ((num & 1) == 1) {
20                num = num - 1;  // Odd number: subtract 1
21            } else {
22                num = num >> 1;  // Even number: divide by 2 (right shift by 1)
23            }
24          
25            // Increment the step counter
26            stepCount++;
27        }
28      
29        return stepCount;
30    }
31}
32
1class Solution {
2public:
3    int numberOfSteps(int num) {
4        int stepCount = 0;
5      
6        // Continue until num becomes 0
7        while (num) {
8            // Check if num is odd (last bit is 1) or even (last bit is 0)
9            // If odd: subtract 1; If even: divide by 2 (right shift by 1)
10            num = (num & 1) ? (num - 1) : (num >> 1);
11          
12            // Increment the step counter
13            ++stepCount;
14        }
15      
16        return stepCount;
17    }
18};
19
1/**
2 * Counts the number of steps to reduce a number to zero.
3 * In each step: if the number is even, divide it by 2; if odd, subtract 1.
4 * 
5 * @param num - The input number to be reduced to zero
6 * @returns The number of steps required
7 */
8function numberOfSteps(num: number): number {
9    // Initialize step counter
10    let stepCount = 0;
11  
12    // Continue until the number becomes zero
13    while (num > 0) {
14        // Check if the number is odd using bitwise AND
15        if (num & 1) {
16            // If odd, subtract 1
17            num = num - 1;
18        } else {
19            // If even, divide by 2 using unsigned right shift
20            num = num >>> 1;
21        }
22      
23        // Increment the step counter
24        stepCount++;
25    }
26  
27    // Return the total number of steps
28    return stepCount;
29}
30

Time and Space Complexity

Time Complexity: O(log n)

The algorithm processes the number num by either subtracting 1 (if odd) or dividing by 2 (if even) until it reaches 0. The key insight is that each operation reduces the problem size:

  • When num is odd, we subtract 1, making it even
  • When num is even, we right shift (divide by 2), which reduces the number of bits

In the worst case, for a number with k bits, we need at most 2k - 1 operations (alternating between subtracting 1 and dividing by 2). Since a number n has approximately log₂(n) bits, the time complexity is O(log n).

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space:

  • Variable ans to count the steps
  • The input num is modified in place
  • No additional data structures are used

The space usage doesn't grow with the input size, making it constant space complexity.

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

Common Pitfalls

1. Inefficient Condition Checking and Operations

A common pitfall is using less efficient operations for checking odd/even and performing division:

Problematic Code:

def numberOfSteps(self, num: int) -> int:
    step_count = 0
    while num > 0:
        if num % 2 == 1:  # Less efficient modulo operation
            num = num - 1
        else:
            num = num / 2  # Using float division instead of integer division
        step_count += 1
    return step_count

Issues:

  • Using num % 2 instead of num & 1 for odd/even checking is slower
  • Using / creates a float, which can cause issues with large numbers and requires type conversion
  • Not using in-place operations misses optimization opportunities

Solution: Use bitwise operations and ensure integer division:

if num & 1:  # Bitwise AND for odd check
    num -= 1  # In-place subtraction
else:
    num >>= 1  # Bitwise right shift (integer division by 2)

2. Edge Case Handling for Zero

While the current solution handles zero correctly (returns 0 steps), developers might overthink and add unnecessary special case handling:

Overcomplicated Code:

def numberOfSteps(self, num: int) -> int:
    if num == 0:  # Unnecessary special case
        return 0
    step_count = 0
    while num > 0:
        # ... rest of the logic

Solution: The while loop naturally handles zero by not executing at all, returning 0 steps. No special case needed.

3. Alternative One-Line Implementation Pitfall

Some might try to optimize this into a mathematical formula but miss edge cases:

Problematic Approach:

def numberOfSteps(self, num: int) -> int:
    if num == 0:
        return 0
    # Trying to use bit manipulation formula
    return bin(num).count('1') + len(bin(num)) - 3

Issues:

  • This formula counts the number of 1s in binary representation plus the bit length minus 3
  • While mathematically correct for most cases, it's less readable and harder to understand
  • The -3 accounts for the '0b' prefix and adjustments, making it error-prone

Solution: Stick with the simulation approach for clarity and maintainability. The performance difference is negligible for reasonable input sizes.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What is the best way of checking if an element exists in an unsorted array once in terms of time complexity? Select the best that applies.


Recommended Readings

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

Load More