题目
题目链接:力扣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 <= 5 * 10^4
解题思路
👉调用函数
这种方法主要是调用库函数解决,由于 C++
的 sort
函数可以排序几乎任何类型的数组,所以包括 string
,而对 string
类型的排序是字典序排序。所以可以把数字转换为字符串类型,再对其进行 sort
排序,之后将其赋给 int
型数组即可。但用这种方法不满足题意,题目要求使用 O(1)
的额外空间算法,所以可以用常规方法。
转换函数:
- 数字转换为字符串:
to_string()
- 字符串转换为数字:
stoi()
👉常规解法
题目没有为难人,只让我们输出从 1
到 n
的字典序。所以可以发现一个规律(比如n=110
):
[1,10,100,101,…109,11,110,12,13,14,…]
由于字典序的排序是第一个字母的权重最大,依次向后递减的。当前面的数字相等时,判断后面数字的大小,大的放后面,小的放前面。所以利用这个特点可以有如下思路:
nums[i] = cur;
if (cur * 10 <= n)
cur *= 10;
else {
if (cur >= n)
cur /= 10;
cur ++;
while (cur % 10 == 0)
cur /= 10;
}
再加上一个循环和 cur
的初值就是这题的完整代码了。
代码(C++)
方法一
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> nums;
vector<string> str;
for (int i = 1; i <= n; ++ i)
str.push_back(to_string(i));
sort(str.begin(), str.end());
for (int i = 0; i < n; ++ i)
nums.push_back(stoi(str[i]));
return nums;
}
};
方法二
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> nums(n);
int cur = 1;
for (int i = 0; i < n; ++ i) {
nums[i] = cur;
if (cur * 10 <= n)
cur *= 10;
else {
if (cur >= n)
cur /= 10;
cur ++;
while (cur % 10 == 0)
cur /= 10;
}
}
return nums;
}
};
总结
拿到题目的第一思路就是使用函数解决,但是有些函数在有些比赛或面试中是不允许使用的,所以最好使用最常规的方法解题。本题的常规方法能想到不容易,但如果慢慢调试应该可以写出来。
不论是函数还是常规方法都应该掌握,函数更便捷,常规方法更锻炼思维。