题目
方法一-不考虑大数问题的简单解法
最大的 n 位数为 1 0 n − 1 10^n-1 10n−1
class Solution {
public int[] printNumbers(int n) {
int end = (int)Math.pow(10, n) - 1;
int[] res = new int[end];//创建整数列表
//填充结果列表
for(int i = 0; i < end; i++){
res[i] = i + 1;
}
return res;
}
}
- 时间复杂度: O ( 1 0 n ) O(10^n) O(10n)
- 空间复杂度: O ( 1 ) O(1) O(1)(列表作为返回结果,不计入额外空间)
方法二-考虑大数越界情况的打印
需要解决以下几个问题:
a. 大数的变量类型选择
数字的取值范围始终受限,因此选择用字符串String类型
b. 字符串集的生成
原本使用 int 类型时结果列表中的数字是递增的,每轮加1即可,现在使用String类型,通过进位操作效率较低,例如"999"到"1000"需要从个位到百位循环判断,进位3次。
我们可以借助分治算法的思想,递归生成 n 位 0~9 的全排列。例如 n = 3 时,可以先固定百位为 0~9,按顺序依次开启十位的递归,最后再固定个位。
c. 删除高位多余的0
例如 00, 01, 02,…,应该显示为 0, 1, 2,…
我们可以定义一个变量
s
t
a
r
t
start
start 来规定字符串的左边界,例如n = 2时,添加的数字字符串为 num[start: ],那么当数字为1~9时令
s
t
a
r
t
=
1
start=1
start=1 ,当数字为10~99时令
s
t
a
r
t
=
0
start=0
start=0
左边界的变化规律:例如 n = 3 时,在"009"到"010"、"099"到"100"时需要将左边界减1,分别是从2减到1、从1减到0。设数字各位中 9 的数量为
n
i
n
e
nine
nine ,各位均为9时:
n
−
s
t
a
r
t
=
n
i
n
e
n-start=nine
n−start=nine
统计
n
i
n
e
nine
nine :固定第
x
x
x 位时,当
i
=
9
i=9
i=9时将
n
i
n
e
nine
nine加1,回溯前恢复(即减1)。
d. 跳过0
在C.的基础上跳过一开始的0,列表直接从1开始
class Solution {
StringBuilder res;
int nine = 0, start, n;
char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
public String printNumbers(int n) {
this.n = n;
res = new StringBuilder();//字符串集
num = new char[n];//长度为n的字符列表
start = n - 1;//左边界初始化
dfs(0);//全排列递归
res.deleteCharAt(res.length() - 1);//删除最后多余的逗号
return res.toString();
}
void dfs(int x){
if(x == n){//已固定完所有位,迭代终止
String s = String.valueOf(num).substring(start);//用删除了高位多余的0后的字符列表创建字符串
if(!s.equals("0"))res.append(s + ",");//将非"0"的数字字符串添加到res尾部,并用逗号隔开
if(n - start == nine)start--;//规定字符串的左边界
return;
}
for(char i : loop){
if(i == '9')nine++;//统计数字各位中9的数量
num[x] = i;//固定第x位
dfs(x + 1);//开启后一位的递归
}
nine--;//回溯前恢复9的数量
}
}
- 时间复杂度: O ( 1 0 n ) O(10^n) O(10n)
- 空间复杂度: O ( 1 0 n ) O(10^n) O(10n),这里返回的是长字符串,额外使用的结果列表 res 长度为 1 0 n − 1 10^n-1 10n−1,,各数字字符串的长度区间为1, 2, …, n,故占用了 O ( 1 0 n ) O(10^n) O(10n)的额外空间。