Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using trie strategy.
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.
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 * 104Problem summary: 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.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Trie
13
2
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #386: Lexicographical Numbers
class Solution {
public List<Integer> lexicalOrder(int n) {
List<Integer> ans = new ArrayList<>(n);
int v = 1;
for (int i = 0; i < n; ++i) {
ans.add(v);
if (v * 10 <= n) {
v *= 10;
} else {
while (v % 10 == 9 || v + 1 > n) {
v /= 10;
}
++v;
}
}
return ans;
}
}
// Accepted solution for LeetCode #386: Lexicographical Numbers
func lexicalOrder(n int) (ans []int) {
v := 1
for i := 0; i < n; i++ {
ans = append(ans, v)
if v*10 <= n {
v *= 10
} else {
for v%10 == 9 || v+1 > n {
v /= 10
}
v++
}
}
return
}
# Accepted solution for LeetCode #386: Lexicographical Numbers
class Solution:
def lexicalOrder(self, n: int) -> List[int]:
ans = []
v = 1
for _ in range(n):
ans.append(v)
if v * 10 <= n:
v *= 10
else:
while v % 10 == 9 or v + 1 > n:
v //= 10
v += 1
return ans
// Accepted solution for LeetCode #386: Lexicographical Numbers
impl Solution {
pub fn lexical_order(n: i32) -> Vec<i32> {
let mut ans = Vec::with_capacity(n as usize);
let mut v = 1;
for _ in 0..n {
ans.push(v);
if v * 10 <= n {
v *= 10;
} else {
while v % 10 == 9 || v + 1 > n {
v /= 10;
}
v += 1;
}
}
ans
}
}
// Accepted solution for LeetCode #386: Lexicographical Numbers
function lexicalOrder(n: number): number[] {
const ans: number[] = [];
let v = 1;
for (let i = 0; i < n; ++i) {
ans.push(v);
if (v * 10 <= n) {
v *= 10;
} else {
while (v % 10 === 9 || v === n) {
v = Math.floor(v / 10);
}
++v;
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Store all N words in a hash set. Each insert/lookup hashes the entire word of length L, giving O(L) per operation. Prefix queries require checking every stored word against the prefix — O(N × L) per prefix search. Space is O(N × L) for storing all characters.
Each operation (insert, search, prefix) takes O(L) time where L is the word length — one node visited per character. Total space is bounded by the sum of all stored word lengths. Tries win over hash sets when you need prefix matching: O(L) prefix search vs. checking every stored word.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.