
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:
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'.
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.
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.
For each number constructed, check that it does not exceed
n
. If it does not, continue building sequentially larger numbers from it.This method naturally enforces lexicographical order since it constructs numbers by appending digits to the end before moving to the next highest initial digit.
Note the
O(n)
time complexitty arises because each acceptable number undern
is considered exactly once, and the building process stops as soon as the numbers exceedn
. TheO(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
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:
- Initialize a
resultOrder
vector to hold the ordered numbers and setcurrent
as the starting number (1). - Use a for-loop to iterate for each number up to
maxNum
:- Add the
current
number toresultOrder
. - If multiplying
current
by 10 is still within the bounds ofmaxNum
, multiplycurrent
by 10 to explore deeper in that number path. - If not (either
current
is at 9 orcurrent
exceedsmaxNum
), peel off the last digit by dividingcurrent
by 10 until the number can be incremented to remain within the bounds of lexicographical order ormaxNum
. - Increment
current
after adjusting.
- Add the
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.
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:
- Initialize an empty list
result
that will store the numbers in lexicographical order. - Start with the number
1
as the smallest lexicographic integer. - Use a loop to generate the next number based on the current number (
num
). - Inside the loop, add
num
to the listresult
. - Check if multiplying
num
by 10 will not exceedn
. If not, updatenum
by multiplying by 10. - If
num * 10
exceedsn
, find the next appropriate number by dividingnum
by 10 until finding a number that, when incremented, does not exceedn
and is not ending in 9. - 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.
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:
- Initialize an empty list
result_list
to store the results and setstart_num
to 1. - Loop from 1 to
max_val
:- Append the current
start_num
toresult_list
. - If
start_num
multiplied by 10 is less than or equal tomax_val
, multiplystart_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 thanmax_val
). If it is, dividestart_num
by 10 until these conditions are no longer met. - Then, increment
start_num
by 1 to move to the next potential starting point.
- Append the current
- 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.
No comments yet.