Given an integer n
, return a list of integers from 1
to n
in lexicographical (dictionary) order.
For example, if n = 13
, the output should be [1,10,11,12,13,2,3,4,5,6,7,8,9]
.
1
to n
(inclusive).
At first glance, the problem seems straightforward: generate all numbers from 1
to n
, convert them to strings, sort them lexicographically, and convert them back to integers. However, this approach is inefficient:
n
.Since the problem asks for an O(n) time solution and minimal extra space, we need a different approach. The key is to generate the numbers directly in lexicographical order, without sorting.
This leads us to think recursively or iteratively about how numbers look in lexicographical order, similar to traversing a tree where each node's children are formed by appending digits.
To generate numbers from 1
to n
in lexicographical order efficiently, we can simulate a preorder traversal of a 10-ary tree:
1
through 9
.x
has up to 10 children: x*10, x*10+1, ..., x*10+9
, as long as they do not exceed n
.
We start from 1
, then go as deep as possible by multiplying by 10 (i.e., 1, 10, 100, ...), then backtrack and increment to the next sibling (i.e., 2, then 20, 200, ...), and so on.
curr = 1
.curr
to the result.curr * 10 ≤ n
, move to curr * 10
(go deeper).curr % 10 != 9
and curr + 1 ≤ n
, increment curr
(move to next sibling).curr
by 10 until the last digit is not 9, then increment (move up and right in the tree).n
numbers are collected.This approach ensures we visit every number in lexicographical order, without sorting or extra storage.
Let's consider n = 13
:
The output is: [1,10,11,12,13,2,3,4,5,6,7,8,9]
class Solution:
def lexicalOrder(self, n: int) -> list[int]:
res = []
curr = 1
for _ in range(n):
res.append(curr)
if curr * 10 <= n:
curr *= 10
else:
if curr % 10 != 9 and curr + 1 <= n:
curr += 1
else:
while (curr // 10) % 10 == 9 or curr + 1 > n:
curr //= 10
curr += 1
return res
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> res;
int curr = 1;
for (int i = 0; i < n; ++i) {
res.push_back(curr);
if (curr * 10 <= n) {
curr *= 10;
} else {
if (curr % 10 != 9 && curr + 1 <= n) {
curr += 1;
} else {
while ((curr / 10) % 10 == 9 || curr + 1 > n) {
curr /= 10;
}
curr += 1;
}
}
}
return res;
}
};
class Solution {
public List<Integer> lexicalOrder(int n) {
List<Integer> res = new ArrayList<>();
int curr = 1;
for (int i = 0; i < n; i++) {
res.add(curr);
if (curr * 10 <= n) {
curr *= 10;
} else {
if (curr % 10 != 9 && curr + 1 <= n) {
curr += 1;
} else {
while ((curr / 10) % 10 == 9 || curr + 1 > n) {
curr /= 10;
}
curr += 1;
}
}
}
return res;
}
}
var lexicalOrder = function(n) {
const res = [];
let curr = 1;
for (let i = 0; i < n; i++) {
res.push(curr);
if (curr * 10 <= n) {
curr *= 10;
} else {
if (curr % 10 !== 9 && curr + 1 <= n) {
curr += 1;
} else {
while (Math.floor(curr / 10) % 10 === 9 || curr + 1 > n) {
curr = Math.floor(curr / 10);
}
curr += 1;
}
}
}
return res;
};
n
.
The key insight is to generate numbers in lexicographical order without sorting, by simulating a preorder traversal of a 10-ary tree. This allows us to achieve O(n) time and O(1) extra space, meeting the problem's constraints. The approach is elegant because it leverages the structure of numbers and their string representations, and avoids unnecessary computation.