Facebook Pixel

1256. Encode Number 🔒

MediumBit ManipulationMathString
Leetcode Link

Problem Description

Given a non-negative integer num, you need to return its encoded string representation based on a special encoding pattern.

The encoding follows a specific rule that can be observed from the given table:

  • 0 encodes to ""
  • 1 encodes to "0"
  • 2 encodes to "1"
  • 3 encodes to "00"
  • 4 encodes to "01"
  • 5 encodes to "10"
  • 6 encodes to "11"
  • 7 encodes to "000"
  • And so on...

Looking at the pattern, we can see that:

  • Numbers 0 maps to empty string
  • Numbers 1-2 map to 1-bit binary strings ("0", "1")
  • Numbers 3-6 map to 2-bit binary strings ("00", "01", "10", "11")
  • Numbers 7-14 map to 3-bit binary strings
  • The pattern continues with each group having twice as many numbers as the previous

The key insight is that if we add 1 to the input number and convert it to binary, then remove the leading 1 bit, we get the desired encoding. For example:

  • num = 0: 0 + 1 = 1 → binary "1" → remove leading 1 → ""
  • num = 1: 1 + 1 = 2 → binary "10" → remove leading 1 → "0"
  • num = 3: 3 + 1 = 4 → binary "100" → remove leading 1 → "00"

Your task is to implement this encoding function that takes a non-negative integer and returns its encoded string.

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

Intuition

Looking at the encoding pattern, we notice that the encoded strings follow a specific structure. The empty string comes first, then all possible 1-bit strings ("0", "1"), then all possible 2-bit strings ("00", "01", "10", "11"), and so on.

Let's group the numbers by the length of their encoded strings:

  • Length 0: num = 0""
  • Length 1: num = 1, 2"0", "1"
  • Length 2: num = 3, 4, 5, 6"00", "01", "10", "11"
  • Length 3: num = 7, 8, 9, 10, 11, 12, 13, 14"000", "001", ..., "111"

We can see that:

  • 1 number maps to length 0
  • 2 numbers map to length 1
  • 4 numbers map to length 2
  • 8 numbers map to length 3

This is a pattern of powers of 2! The total count of numbers from 0 to num is num + 1.

Now, if we think about binary representation, a number n in binary essentially tells us:

  • The highest bit tells us how many bits we need
  • The remaining bits give us the exact binary pattern

For example, if num = 5:

  • num + 1 = 6 = 110 in binary
  • The highest bit 1 indicates we're in the group of 2-bit encodings
  • The remaining bits 10 give us the exact encoding

This reveals the elegant solution: by adding 1 to num, we shift it into a binary representation where the highest bit acts as a "group indicator" and the remaining bits form the actual encoding. Removing that highest bit (which is always 1) gives us the desired encoded string.

The transformation bin(num + 1)[3:] works because:

  • bin() returns a string like "0b110"
  • The first two characters "0b" are the binary prefix
  • The third character is always "1" (the highest bit for any positive number)
  • Characters from index 3 onwards are exactly our encoding

Learn more about Math patterns.

Solution Approach

The solution uses bit manipulation to transform the input number into its encoded form. The implementation is remarkably concise:

def encode(self, num: int) -> str:
    return bin(num + 1)[3:]

Let's break down the algorithm step by step:

Step 1: Add 1 to the input number

  • We compute num + 1 to shift the number into a form where its binary representation encodes both the length and pattern information.

Step 2: Convert to binary string

  • bin(num + 1) converts the result to a binary string representation
  • For example: bin(5) returns "0b101"

Step 3: Extract the encoding

  • The bin() function returns a string with prefix "0b" (2 characters)
  • The third character is always "1" for any positive number (the highest bit)
  • We slice from index 3 onwards using [3:] to get the remaining bits

Why this works:

  • When we add 1 to num, we're essentially mapping:

    • 01 (binary: "0b1")
    • 12 (binary: "0b10")
    • 23 (binary: "0b11")
    • 34 (binary: "0b100")
    • And so on...
  • After removing the prefix "0b" and the leading "1":

    • "0b1""" (empty string)
    • "0b10""0"
    • "0b11""1"
    • "0b100""00"
    • "0b101""01"

This elegant approach leverages the natural binary representation to directly generate the encoded string without any conditional logic or loops. The time complexity is O(log n) for the binary conversion, and the space complexity is also O(log n) for storing the binary string.

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 walk through encoding the number 5 step by step:

Given: num = 5

Step 1: Add 1 to the input

  • 5 + 1 = 6

Step 2: Convert to binary string

  • bin(6) returns "0b110"
  • Breaking this down:
    • "0b" is the binary prefix Python adds
    • "110" is the binary representation of 6

Step 3: Extract the encoding by slicing from index 3

  • The string "0b110" has indices:
    • Index 0: '0'
    • Index 1: 'b'
    • Index 2: '1' (the leading bit, always 1 for positive numbers)
    • Index 3: '1'
    • Index 4: '0'
  • "0b110"[3:] gives us "10"

Result: The encoded string for 5 is "10"

Let's verify with another example, num = 7:

  • 7 + 1 = 8
  • bin(8) = "0b1000"
  • "0b1000"[3:] = "000" (taking characters from index 3 onwards)
  • Result: "000"

We can see the pattern: adding 1 shifts our number into a binary form where removing the prefix and leading 1 gives us exactly the encoding we need. The leading 1 essentially marks the "group" (how many bits), while the remaining digits form the actual encoded value within that group.

Solution Implementation

1class Solution:
2    def encode(self, num: int) -> str:
3        """
4        Encodes an integer into a binary string representation.
5      
6        The encoding scheme works by:
7        1. Adding 1 to the input number
8        2. Converting to binary
9        3. Removing the '0b' prefix and the most significant bit
10      
11        This creates a unique binary encoding for each non-negative integer.
12      
13        Args:
14            num: A non-negative integer to encode
15          
16        Returns:
17            A binary string encoding of the input number
18          
19        Examples:
20            0 -> "" (bin(1) = '0b1', slice [3:] gives "")
21            1 -> "0" (bin(2) = '0b10', slice [3:] gives "0")
22            2 -> "1" (bin(3) = '0b11', slice [3:] gives "1")
23            3 -> "00" (bin(4) = '0b100', slice [3:] gives "00")
24        """
25        # Add 1 to num and convert to binary string
26        binary_representation = bin(num + 1)
27      
28        # Remove '0b' prefix (2 chars) and the leading '1' bit (1 char)
29        # This effectively removes the most significant bit
30        encoded_string = binary_representation[3:]
31      
32        return encoded_string
33
1class Solution {
2    /**
3     * Encodes an integer into a binary string representation.
4     * 
5     * The encoding scheme works by:
6     * 1. Adding 1 to the input number
7     * 2. Converting the result to binary
8     * 3. Removing the leading '1' bit
9     * 
10     * This creates a bijective mapping where:
11     * - 0 -> "" (empty string)
12     * - 1 -> "0"
13     * - 2 -> "1"
14     * - 3 -> "00"
15     * - 4 -> "01"
16     * - 5 -> "10"
17     * - 6 -> "11"
18     * - 7 -> "000"
19     * etc.
20     * 
21     * @param num The non-negative integer to encode
22     * @return The encoded binary string
23     */
24    public String encode(int num) {
25        // Add 1 to shift the number into the next binary range
26        int shiftedNumber = num + 1;
27      
28        // Convert to binary string representation
29        String binaryString = Integer.toBinaryString(shiftedNumber);
30      
31        // Remove the first character (the leading '1' bit)
32        // This gives us the encoded result
33        return binaryString.substring(1);
34    }
35}
36
1class Solution {
2public:
3    string encode(int num) {
4        // Increment the input number by 1
5        // This is the key insight: encoding of n is the binary representation of (n+1) without the leading 1
6        num++;
7      
8        // Convert the incremented number to a 32-bit binary string
9        bitset<32> binaryRepresentation(num);
10        string binaryString = binaryRepresentation.to_string();
11      
12        // Find the position of the first '1' bit (leftmost 1)
13        int firstOnePosition = 0;
14        while (binaryString[firstOnePosition] == '0') {
15            firstOnePosition++;
16        }
17      
18        // Return the substring after the first '1' bit
19        // This removes all leading zeros and the first '1'
20        return binaryString.substr(firstOnePosition + 1);
21    }
22};
23
1/**
2 * Encodes a non-negative integer to its shortened binary representation
3 * by adding 1 and removing the leading '1' bit.
4 * 
5 * The algorithm works by:
6 * 1. Incrementing the input number by 1
7 * 2. Converting to binary string representation
8 * 3. Removing the first character (which is always '1' after incrementing)
9 * 
10 * This encoding scheme maps:
11 * 0 -> "" (empty string)
12 * 1 -> "0"
13 * 2 -> "1"
14 * 3 -> "00"
15 * 4 -> "01"
16 * 5 -> "10"
17 * 6 -> "11"
18 * 7 -> "000"
19 * ...and so on
20 * 
21 * @param num - The non-negative integer to encode
22 * @returns The encoded binary string
23 */
24function encode(num: number): string {
25    // Increment the number by 1 to prepare for encoding
26    const incrementedNum: number = num + 1;
27  
28    // Convert the incremented number to binary string
29    const binaryString: string = incrementedNum.toString(2);
30  
31    // Remove the first character (leading '1') to get the encoded result
32    const encodedString: string = binaryString.slice(1);
33  
34    return encodedString;
35}
36

Time and Space Complexity

The time complexity is O(log n), where n is the value of the input number num. This is because:

  • The bin() function needs to convert the decimal number (num + 1) to its binary representation, which requires examining each bit position. The number of bits needed to represent a number n is ⌊log₂(n)⌋ + 1, which is O(log n).
  • The slicing operation [3:] creates a substring, which in the worst case is proportional to the length of the binary string, also O(log n).

The space complexity is O(log n), where n is the value of the input number num. This is because:

  • The bin() function creates a string to store the binary representation of (num + 1), which requires O(log n) space since the number of bits is logarithmic to the value.
  • The slicing operation [3:] creates a new string that stores the result, which also requires O(log n) space in the worst case.

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

Common Pitfalls

1. Incorrect Slicing Index

One of the most common mistakes is using the wrong slicing index when removing the prefix and leading bit. Developers might accidentally use:

  • bin(num + 1)[2:] - This only removes the "0b" prefix but keeps the leading '1'
  • bin(num + 1)[1:] - This keeps the 'b' character in the result
  • bin(num + 1)[:3] - This returns the prefix instead of the encoding

Incorrect Example:

def encode(self, num: int) -> str:
    return bin(num + 1)[2:]  # Wrong! Returns "1", "10", "11", "100"...

Solution: Always use [3:] to skip both the "0b" prefix (2 characters) and the leading '1' bit (1 character).

2. Forgetting to Add 1

Another pitfall is directly converting num to binary without adding 1 first:

def encode(self, num: int) -> str:
    return bin(num)[3:]  # Wrong! Breaks the encoding pattern

This would map 0 → error (index out of range), 1 → "", 2 → "0", which doesn't match the required encoding.

Solution: Always remember to compute num + 1 before the binary conversion.

3. Edge Case with num = 0

Some developers might worry about the edge case when num = 0 and try to add special handling:

def encode(self, num: int) -> str:
    if num == 0:
        return ""
    return bin(num + 1)[3:]  # Unnecessary special case

Solution: The algorithm naturally handles num = 0. When num = 0, bin(1) = "0b1", and "0b1"[3:] returns an empty string "", which is correct.

4. String Manipulation Instead of Slicing

Using string methods like replace() or lstrip() can lead to incorrect results:

def encode(self, num: int) -> str:
    return bin(num + 1).replace("0b1", "")  # Wrong for larger numbers!

This would incorrectly remove "0b1" pattern anywhere in the string, not just at the beginning.

Solution: Use slicing [3:] which precisely removes the first three characters regardless of the remaining content.

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

What data structure does Breadth-first search typically uses to store intermediate states?


Recommended Readings

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

Load More