HomeLeetcode386. Lexicographical Numbers - Leetcode Solutions

386. Lexicographical Numbers – Leetcode Solutions

Description

Given an integer n, return all the numbers in the range [1, n] sorted in lexicographical order.

You must write an algorithm that runs in O(n) time and uses O(1) extra space. 

Examples:

Example 1:

Input: n = 13
Output: [1,10,11,12,13,2,3,4,5,6,7,8,9]

Example 2:

Input: n = 2
Output: [1,2]

Solution in Python

Solution Strategy

To achieve O(n) time complexity and O(1) extra space complexity, we use a depth-first traversal approach to build numbers in lexicographical order by incrementing digits.

  1. Lexicographical Traversal:
    • Start with 1 and try to explore as deep as possible by appending 0 to the current number (e.g., from 1 to 10).
    • If we reach a number greater than n, backtrack to explore the next number in lexicographical order by incrementing the current number.
    • Repeat this traversal until we have collected all numbers up to n.
  2. Traversal Rules:
    • If we can “go deeper” by appending 0 to the current number (e.g., from 1 to 10), do so.
    • If the current number exceeds n, backtrack by dividing by 10 (removing the last digit).
    • If the current number ends in 9 or going to the next number would exceed n, backtrack and increment.
  3. Time Complexity:
    • Each number from 1 to n is added in lexicographical order directly, resulting in O(n) operations.
    • No extra lists or recursion stacks are required, giving O(1) space complexity (excluding the output list).
Python
class Solution:
    def lexicalOrder(self, n: int) -> List[int]:
        result = []  # List to store lexicographical order of numbers
        current = 1  # Start with the smallest lexicographical number
        
        for _ in range(n):
            result.append(current)  # Add the current number to the result list
            
            # Try to go deeper by appending a '0' (multiply by 10)
            if current * 10 <= n:
                current *= 10
            else:
                # Otherwise, increment to the next number
                if current >= n:
                    # While current ends with '9' or exceeds `n`, backtrack by removing the last digit
                    current //= 10
                current += 1
                # Remove trailing zeroes caused by overflow from n
                while current % 10 == 0:
                    current //= 10
                    
        return result

Explanation of the Code

  1. Initialization:
    • result holds the final ordered list.
    • current starts at 1, the first number in lexicographical order.
  2. Loop to Build Lexicographical Order:
    • Each iteration appends current to result.
    • Then we decide how to traverse:
      • Go deeper by multiplying current by 10 if current * 10 <= n.
      • If current * 10 > n, try incrementing current to the next lexicographical number.
      • If current exceeds n or ends with 9, backtrack by dividing by 10 to remove the last digit.
  3. Final Adjustments for Trailing Zeroes:
    • If the last increment resulted in trailing zeroes (like 10 becoming 100), remove them by dividing by 10.

Solution in C++

C++
class Solution {
public:
    vector<int> lexicalOrder(int n) {
        // Result vector to store lexicographical order
        vector<int> result;
        
        // Start the traversal from the number 1
        int current = 1;
        
        // We need exactly 'n' numbers in our result, so repeat 'n' times
        for (int i = 0; i < n; ++i) {
            result.push_back(current);
            
            // Try to go deeper (multiply current by 10) if possible
            if (current * 10 <= n) {
                current *= 10;
            } 
            else {
                // Otherwise, if we can't go deeper, increment the number
                // But we need to handle cases where this leads us out of bounds
                while (current % 10 == 9 || current + 1 > n) {
                    current /= 10; // Move up one level in lexicographical hierarchy
                }
                current++; // Move to the next number in the current level
            }
        }
        
        return result;
    }
};

Solution in Javascript

JavaScript
var lexicalOrder = function(n) {
    // Initialize an empty array to store the lexicographical numbers
    let result = [];
    
    // Define a helper function that performs a depth-first traversal to generate numbers lexicographically
    function dfs(current) {
        // Base case: if the current number exceeds n, we stop the recursion
        if (current > n) return;
        
        // Add the current number to the result array
        result.push(current);
        
        // Try to build the next number by adding digits 0 to 9 to the end of `current`
        for (let i = 0; i < 10; i++) {
            let next = current * 10 + i;
            // If the generated number is greater than `n`, break out of the loop
            if (next > n) break;
            // Recursively call dfs with the newly generated number
            dfs(next);
        }
    }
    
    // Start with each number from 1 to 9, since we want lexicographical order
    for (let i = 1; i < 10; i++) {
        dfs(i);
    }
    
    // Return the result array containing all numbers in lexicographical order
    return result;
};

Solution in Java

Java
class Solution {
    public List<Integer> lexicalOrder(int n) {
        List<Integer> result = new ArrayList<>();
        
        // Start the DFS from each number 1 to 9
        for (int i = 1; i <= 9; i++) {
            dfs(i, n, result);
        }
        
        return result;
    }

    // Helper function for depth-first search
    private void dfs(int current, int n, List<Integer> result) {
        // Base case: if the current number exceeds n, return
        if (current > n) {
            return;
        }
        
        // Add the current number to the result list
        result.add(current);
        
        // Explore the next numbers by appending digits 0 to 9
        for (int i = 0; i <= 9; i++) {
            // Generate the next number
            int next = current * 10 + i;
            // If the next number exceeds n, break
            if (next > n) {
                break;
            }
            // Recursively call dfs with the next number
            dfs(next, n, result);
        }
    }
}

Subscribe
Notify of

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Popular