Lexicographical Numbers

Updated on 03 June, 2025
Lexicographical Numbers header image

Problem Statement

Given an integer n, the task is to generate a list of integers from 1 to n and sort them according to their lexicographical order. Lexicographical order is similar to what one might see in a dictionary, where the numbers are sorted as if they are strings. For instance, in lexicographical order, 10 would come before 2 because "10" as a string is less than "2".

The goal is to develop an efficient algorithm that sorts the numbers in O(n) time complexity while utilizing O(1) extra space, meaning the space complexity should not increase with the size of the input.

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]

Constraints

  • 1 <= n <= 5 * 104

Approach and Intuition

To solve this problem efficiently with the given constraints, a specific sort of algorithm is required that can generate the desired order directly:

  1. A fundamental observation about lexicographical sorting is that it behaves like a depth-first search (DFS) in a tree of digit characters where each node can have children from '0' to '9'.

  2. To simulate this in an integer context, start with each digit from 1 to 9 and iteratively build possible numbers from those starting points. For example, start with 1, then build 10, 11, 12,... if they are within bounds, yielding 1 followed by 10, 11, 12, etc.

  3. Use a loop to handle each initial digit, and for each, iterate to attempt constructing the next number in sequence. This involves multiplying the current number by 10 and adding increments from 0 to 9 to access subsequent potential numbers.

  4. For each number constructed, check that it does not exceed n. If it does not, continue building sequentially larger numbers from it.

  5. This method naturally enforces lexicographical order since it constructs numbers by appending digits to the end before moving to the next highest initial digit.

  6. Note the O(n) time complexitty arises because each acceptable number under n is considered exactly once, and the building process stops as soon as the numbers exceed n. The O(1) space is maintained, as no additional storage is needed beyond the loop variables and the current number being constructed.

This iterative approach mimics recursively building a tree and ensures numbers are generated and consumed in the correct order, thus efficiently producing the desired list without requiring a sort operation.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    vector<int> orderedLexical(int maxNum) {
        vector<int> resultOrder;
        int current = 1;

        for (int i = 0; i < maxNum; ++i) {
            resultOrder.push_back(current);

            if (current * 10 <= maxNum) {
                current *= 10;
            } else {
                while (current % 10 == 9 || current >= maxNum) {
                    current /= 10;
                }
                current += 1;
            }
        }

        return resultOrder;
    }
};

The solution implements a function to generate a list of integers in lexicographical order up to a given maximum number using C++. The function orderedLexical returns a vector of integers, generating numbers starting from 1 and moving lexicographically without direct string comparison.

Here's a breakdown of how the function achieves the lexicographical sorting:

  1. Initialize a resultOrder vector to hold the ordered numbers and set current as the starting number (1).
  2. Use a for-loop to iterate for each number up to maxNum:
    • Add the current number to resultOrder.
    • If multiplying current by 10 is still within the bounds of maxNum, multiply current by 10 to explore deeper in that number path.
    • If not (either current is at 9 or current exceeds maxNum), peel off the last digit by dividing current by 10 until the number can be incremented to remain within the bounds of lexicographical order or maxNum.
    • Increment current after adjusting.

This approach, focusing on numeric manipulations, avoids the higher computational cost of generating all possible numbers, converting to strings, and sorting them. Instead, it intelligently navigates through possible number sequences in the correct lexicographic sequence by treating the numbers as digit trees.

java
class Solution {

    public List<Integer> sortedIntegers(int n) {
        List<Integer> result = new ArrayList<>();
        int num = 1;

        for (int i = 0; i < n; i++) {
            result.add(num);

            if (num * 10 <= n) {
                num *= 10;
            } else {
                while (num % 10 == 9 || num >= n) {
                    num /= 10;
                }
                num += 1;
            }
        }

        return result;
    }
}

This solution in Java focuses on generating a list of integers in lexicographical order up to a given number, n. It leverages a fundamental understanding of numerical operations and list manipulation to achieve the desired result.

Overview of the Approach:

  1. Initialize an empty list result that will store the numbers in lexicographical order.
  2. Start with the number 1 as the smallest lexicographic integer.
  3. Use a loop to generate the next number based on the current number (num).
  4. Inside the loop, add num to the list result.
  5. Check if multiplying num by 10 will not exceed n. If not, update num by multiplying by 10.
  6. If num * 10 exceeds n, find the next appropriate number by dividing num by 10 until finding a number that, when incremented, does not exceed n and is not ending in 9.
  7. Continue this until the list contains n integers.

Key Points to Note:

  • Multiplying by 10 shifts the focus to the next lexicographical tier (like moving from 1 to 10, 10 to 100).
  • Once reaching the maximum or end of a tier (indicated by numbers ending in 9 or exceeding n), the algorithm scales back (dividing by 10) and then steps forward by incrementing.
  • This method ensures that every integer from 1 to n is considered without directly sorting, thus optimizing the generation of the list based on lexicographical order.

This program efficiently populates each number in its correct lexicographical position relative to accumulative integer positioning, ensuring both correctness and optimal performance by limiting recalculations and refraining from using additional sorting mechanisms. This results in a fast and efficient solution to the problem of listing numbers lexicographically.

python
class Solution:
    def generateLexical(self, max_val: int) -> List[int]:
        result_list = []
        start_num = 1

        for _ in range(max_val):
            result_list.append(start_num)

            if start_num * 10 <= max_val:
                start_num *= 10
            else:
                while start_num % 10 == 9 or start_num >= max_val:
                    start_num //= 10
                start_num += 1

        return result_list

The provided Python code outlines a method generateLexical inside a Solution class that generates numbers in lexicographical order up to a given max_val. The code works as follows:

  1. Initialize an empty list result_list to store the results and set start_num to 1.
  2. Loop from 1 to max_val:
    • Append the current start_num to result_list.
    • If start_num multiplied by 10 is less than or equal to max_val, multiply start_num by 10.
    • If not, check if start_num is at the last number for the current range (whether it ends with a 9 or is greater than max_val). If it is, divide start_num by 10 until these conditions are no longer met.
    • Then, increment start_num by 1 to move to the next potential starting point.
  3. Return the populated result_list containing the numbers in lexicographical order.

This approach leverages mathematical operations to build the sequence directly, ensuring efficient and logical progression through possible values without needing to sort them explicitly after generation.

Comments

No comments yet.