小知识,大挑战!本文正在参与「程序员必备小知识」创作活动。
问题
打印1到最大的n位数
力扣链接
考察要点
大数问题, 递归思想
思路1
首先根据传入的位n, 来确定它的最大值, 也就是10的n次方减1
然后, 使用for循环来遍历从1到这个最大值的数
时间复杂度: O(10n)
代码1
public int[] printNumbers(int n) {
if (n <= 0) return new int[]{};
// 10的n次方减1, 就是n位数的最大佬
int end = (int)Math.pow(10, n) - 1;
int[] res = new int[end];
// 从 0开始, 遍历到最大值
for (int i = 0; i < end; i++) {
res[i] = i + 1;
}
return res;
}
思路2
我们可以使用全排列的思想进行数字的排列, 并且可以使用递归来完成这个全排列
例如: 如果n为2, 那么从高位到低位的全排列顺序为
00, 01, 02, ..., 09
10, 11, 12, ..., 19
当然我们在使用字符数组进行全排列的时候, 要注意去掉高位多余的0
当数字为1位时, 我们可以从字符串的最后开始截取1位
当数字为2位时, 我们可以从字符串的最后开始截取2位
代码2
// 用来存储全排列数
int[] res;
// 当前要存放到res中的索引
int count = 0;
// 记录9出现的次数
int nine = 0;
// 根据nine进行相应的调整, 也就是我们要从字符数组中的哪一位开始转换为字符串
int start = 0;
// num为单次排列存储字符的数组
// loop为0-9的数字
char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
public int[] printNumbers2(int n) {
if (n <= 0) return new int[]{};
// 初始化数组, 它有10的n次方个元素
res = new int[(int)Math.pow(10, n) - 1];
// 用来存储每次全排列的数
num = new char[n];
// 如果从低到高打印数字的话, 要从字符数组的最后一个元素开始
start = n - 1;
// 开启全排列
dfs(0, n);
return res;
}
void dfs(int x, int n) {
if(x == n) {
// 字符数组转换为字符串, 并且根据start去掉字符串里高位中的0
String s = String.valueOf(num).substring(start);
// 将字符串转换为整型数据, 存入返回值中
if(!s.equals("0")) res[count++] = Integer.parseInt(s);
// 每当记录9出现的次数多一个时, 就代表字符数组中的值进了一位
if(n - start == nine) start--;
return;
}
for(char i : loop) {
if(i == '9') nine++;
// 全排列, 从高位开始到低位
/*
* 00, 01, 02, 03, ..., 09
* 10, 11, 12, 13, ..., 19
* */
num[x] = i;
dfs(x + 1, n);
}
nine--;
}
总结
通过本题可以学到在解决大数问题的时候, 我们要学会将其转换为字符串或者字符数组来解决该问题. 如果问题中并没有限定取值范围, 或者可以输入任意大小的整数, 那么我们应该考虑大数问题, 可将其转换为字符串或字符数组来进行解决.