一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
题目链接:386. 字典序排数
题目描述
给你一个整数 n ,按字典序返回范围 [1, n] 内所有整数。
你必须设计一个时间复杂度为 O(n) 且使用 O(1) 额外空间的算法。
提示:
示例 1:
输入: n = 13
输出: [1,10,11,12,13,2,3,4,5,6,7,8,9]
示例 2:
输入: n = 2
输出: [1,2]
题意整理
题目非常简短,让我们返回 [1, n] 内所有整数按照字典序排序后的结果,并且有复杂度要求。
解题思路分析
习惯性动作:首先确定题目数据范围 ,这个数据大小是不能接受 的时间复杂度,可以接受的是 和 的时间复杂度。
我们很容易想到的做法是 遍历一遍 n 个数字,将每个数字转换成字符串的形式,然后对其进行 的字符串排序。
显然这样做是可以通过所有测试的,但是不符合题目的要求,题目要求设计一个时间复杂度为 且使用 额外空间的算法,因此我们不能使用直接排序的方法。排序的方法使用了 的时间复杂度, 的空间复杂度。
那我们考虑一下对于一个整数 num,它的下一个字典序整数应该怎么求:
- 首先可以想到的是在
num后面直接添加一个0这肯定是num的下一个字典序整数,但是我们需要考虑当num后面添加一个0后也就是num * 10的大小是否超过了n,因为题目要求我们对n以内的数字进行字典序排序,所以我们可以得到求num的下一个字典序整数方法为:如果num * 10 <= n,那么说明num * 10是num的下一个字典序整数; - 其次我们考虑剩余情况,也就是如果
num * 10 > n的情况:那么我们可以对num进行+1操作,同样我们需要考虑当num + 1后是否超过了n,并且考虑边界情况:当num % 10 == 9时我们对num进行+1操作其实就相当于对num进行(num / 10) + 1操作,那不就是对num的上一层进行+1操作,所以当num * 10 > n时,我们可以求得num的下一个字典序整数方法为:如果num * 10 > n,那么num + 1是下一个字典序整数,但是需要判断num末尾的数位已经搜索完成的情况:如果num % 10 == 9或num + 1 > n,表示num末尾的数位已经搜索完成,我们需要一直回退至num % 10 != 9且num + 1 <= n的那一位进行num + 1操作。这里回退上一位也就是 ,即num = num / 10;
具体实现
- 字典序最小的整数为
num = 1,我们从它开始,然后依次获取下一个字典序整数,加入结果中,结束条件为已经获取到n个整数。 - 对于一个整数
num的下一个字典序整数获取方法:- 当
num * 10 <= n时我们直接num *= 10 - 否则对
num进行+1操作,但是在进行+1操作前需要判断num末尾的数位已经搜索完成的情况,回退至num % 10 != 9且num + 1 <= n的那一位进行num + 1操作。
- 当
复杂度分析
- 时间复杂度:,其中
n为整数的数目。获取下一个字典序整数的最坏时间复杂度为 ,但while循环的迭代次数与num的末尾连续9的数目有关,在整数区间 中,末尾连续的9的数目为k的整数不超过 个,其中 ,因此总迭代次数不超过 ,总时间复杂度为 。 - 空间复杂度:。返回值不计入空间复杂度。
需要注意的是严格来说递归实现的
DFS空间复杂度是 不满足题目要求的 ,而用迭代实现的空间复杂度满足 。
代码实现
class Solution {
public:
vector<int> lexicalOrder(int n) {
//答案数组res
vector<int> res;
res.clear();
//初始化字典序最小的整数为1
int num = 1;
for(int i = 1; i <= n; i++){
//从第1个到第n个按照字典序压入答案数组res
res.push_back(num);
//获取num的下一个字典序整数
if(num * 10 <= n){
num *= 10;
}
else{
//考虑 +1 后大于 n 和 num % 10 = 9 的边界情况
while(num + 1 > n || num % 10 == 9){
//回退上一层
num /= 10;
}
num++;
}
}
return res;
}
};
总结
该题本质上是对一颗节点数量为 10(节点从 0 到 9),形态类似字典树的多阶树进行遍历。此外还有一道类似于这题的进阶版本:440.字典序的第K小数字
结束语
我们总在仰望和羡慕别人,一回头,却发现自己正被别人仰望和羡慕着。其实每个人都有属于自己的幸福,只是你的幸福,常常在别人眼里。与其总是与别人攀比,不如珍惜此刻所拥有的。把握当下的生活,才能通往明天的幸福。