本文已参与「新人创作礼」活动,一起开启掘金创作之路。
| 每日一题做题记录,参考官方和三叶的题解 |
题目要求
【前段时间刚做过类似的更难的一道——leetcode440.字典序的第K小数字【字典序学习】,有简单介绍字典序】
思路一:DFS之递归
字典序想到构建字典树进行DFS遍历,对于当前层的每一个节点依次遍历其子节点,即修改每个数字的末位。第一层为(首位)。
Java
class Solution {
List<Integer> res = new ArrayList<>();
int lim;
public List<Integer> lexicalOrder(int n) {
lim = n;
for(int i = 1; i <= 9; i++) //首位搜索
dfs(i);
return res;
}
void dfs(int cur) {
if(cur > lim)
return;
res.add(cur);
for(int i = 0; i <= 9; i++) //末位搜索
dfs(cur * 10 + i);
}
}
- 时间复杂度:,搜索个节点的树
- 空间复杂度:,忽略递归的额外开销
C++
class Solution {
private:
vector<int> res;
int lim;
void dfs(int cur) {
if(cur > lim)
return;
res.push_back(cur);
for(int i = 0; i <= 9; i++) //末位搜索
dfs(cur * 10 + i);
}
public:
vector<int> lexicalOrder(int n) {
lim = n;
for(int i = 1; i <= 9; i++) //首位搜索
dfs(i);
return res;
}
};
- 时间复杂度:,搜索个节点的树
- 空间复杂度:,忽略递归的额外开销
思路二:DFS之迭代
递归存在额外的空间开销,所以将其改为迭代。
思路大体一致,注意判断边界条件,超过限制值注意回退,不要直接丢了这一支。
Java
class Solution {
public List<Integer> lexicalOrder(int n) {
List<Integer> res = new ArrayList<>();
for(int i = 0, j = 1; i < n; i++) { //首位搜索
res.add(j);
if(j * 10 <= n) //添0
j *= 10;
else {
while(j % 10 == 9 || j + 1 > n) //超了回退
j /= 10;
j++; //末位搜索
}
}
return res;
}
}
- 时间复杂度:
- 空间复杂度:
C++
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> res;
for(int i = 0, j = 1; i < n; i++) { //首位搜索
res.push_back(j);
if(j * 10 <= n) //添0
j *= 10;
else {
while(j % 10 == 9 || j + 1 > n) //超了回退
j /= 10;
j++; //末位搜索
}
}
return res;
}
};
- 时间复杂度:
- 空间复杂度:
总结
算是最近最有意思的题了,但是之前做过字典序,所以很快就有思路,也不太称得上中等难度。
对递归和迭代来回转换的思路方式逐渐熟悉起来。
| 欢迎指正与讨论! |