Hey tech trailblazers! ๐
Today, weโre exploring a deceptively simple but algorithmically clever problem โ LeetCode 386: Lexicographical Numbers. This oneโs all about simulating dictionary-like traversal of numbers from 1
to n
, and weโll solve it in O(n)
time without recursion or heavy data structures. Letโs dive in! ๐ก
๐ Problem Overview
Youโre given an integer n
.
Your goal is to return all numbers from 1
to n
sorted lexicographically, not numerically.
๐ Lexicographical Order = Dictionary order
For example:
Numerical: 1, 2, 3, 4, ..., 10, 11
Lexicographical: 1, 10, 11, 2, 3, ..., 9
๐ 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]
๐ง Intuition & Strategy
If we sort the numbers as strings, itโs easy โ but that costs O(n log n) and uses extra space. โ
The challenge here is to do this in:
- โฑ O(n) time
- ๐พ O(1) extra space (excluding the output array)
โ Observation:
The lexicographical order of numbers can be traversed like a DFS tree, where:
- Going deeper = appending
0
(multiply by 10) - Moving sideways = incrementing by 1 (unless we hit a boundary like
9
orn
)
๐ก Greedy DFS Simulation
Start from 1
, and simulate:
-
If
curr * 10 <= n
โ go to the next depth (i.e.,1
โ10
,2
โ20
, etc.) -
Else, if
curr % 10 != 9
andcurr + 1 <= n
โ move to the next sibling - If we can't move forward (e.g., from
19
,curr = 20
is >n
) โ backtrack usingcurr /= 10
until we can increment again
This mimics DFS without recursion or a stack.
โ๏ธ C++ Code (Optimized)
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> ans;
int curr = 1;
while (ans.size() < n) {
ans.push_back(curr);
if (curr * 10 <= n) {
curr *= 10;
} else {
while (curr % 10 == 9 || curr == n)
curr /= 10;
++curr;
}
}
return ans;
}
};
๐ JavaScript Version
var lexicalOrder = function(n) {
const ans = [];
let curr = 1;
while (ans.length < n) {
ans.push(curr);
if (curr * 10 <= n) {
curr *= 10;
} else {
while (curr % 10 === 9 || curr === n) {
curr = Math.floor(curr / 10);
}
curr++;
}
}
return ans;
};
๐ Python Version
class Solution:
def lexicalOrder(self, n: int) -> list[int]:
result = []
curr = 1
while len(result) < n:
result.append(curr)
if curr * 10 <= n:
curr *= 10
else:
while curr % 10 == 9 or curr == n:
curr //= 10
curr += 1
return result
๐งช Test Case Scenarios
Input: n = 13
Output: [1,10,11,12,13,2,3,4,5,6,7,8,9]
Input: n = 2
Output: [1,2]
Input: n = 1
Output: [1]
Input: n = 100
Output: [1,10,100,11,12,13,14,...,2,20,...,99]
Input: n = 9
Output: [1,2,3,4,5,6,7,8,9] // No depth traversal, just linear
๐งฎ Time & Space Complexity
Time Complexity: O(n)
- Each number is processed exactly once
Space Complexity: O(1)
- No extra data structures used (besides output)
โ This solution fully respects the space and time constraints set by the problem โ making it both elegant and interview-worthy.
โจ Wrap Up
This problem is a brilliant example of how string logic and DFS intuition can be implemented in a space-efficient way.
If you enjoyed the breakdown, consider hitting that โค๏ธ and sharing with fellow devs. Letโs keep growing and solving, one problem at a time! ๐๐ป
Happy coding! ๐
Top comments (4)
pretty cool breaking it down like this - i always get curious if stuff like this mostly comes from grinding problems or if thereโs a trick to picking up patterns faster?
It's just like chess , the more you play, the better you get init.
Easy question, yet loved how you explained it.
Thank you anna
Some comments may only be visible to logged-in visitors. Sign in to view all comments.