一、需求
- 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
说明:
用返回一个整数列表来代替打印
n 为正整数
二、遍历法
2.1 思路分析
- 题目假定了返回的是int数组,故不存在大数越界问题,那么只需要返回存储1 ~ (10^n - 1)的数组即可;
2.2 代码实现
class Solution {
public int[] printNumbers(int n) {
int len = (int)(Math.pow(10, n)) - 1;
int[] res = new int[len];
for(int i = 0; i < len; i++) {
res[i] = i + 1;
}
return res;
}
}
2.3 复杂度分析
- 时间复杂度为;
- 空间复杂度为O(1),列表作为返回结果,不计入额外空间;
三、分治算法
3.1 思路分析
- 规定返回类型为字符串,因为当 n 足够大时,10^n - 1超过int型的范围,故用字符串来存储从1到最大的n位数;
- 详解参考:https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/solution/mian-shi-ti-17-da-yin-cong-1-dao-zui-da-de-n-wei-2/
3.2 获取从0到最大n位数的排列
class Solution {
char[] loop = {'0','1','2','3','4','5','6','7','8','9'};
char[] num;
int n;
StringBuilder res = new StringBuilder();
public String printNumbers(int n) {
this.n = n;
num = new char[n];
dfs(0);
res.deleteCharAt(res.length() - 1);
return res.toString();
}
//该方法的作用是固定当前位
public void dfs(int x) {
if(x == n) {
res.append(num).append(",");
return;
}
for(char i : loop) {
num[x] = i;
dfs(x + 1);
}
}
public static void main(String[] args) {
Solution s = new Solution();
String str = s.printNumbers(2);
System.out.println(str);
}
}
3.3 打印从1到最大的n位数(返回字符串)
- 上面的代码存在两个问题:①当n = 2时,打印00 01 02 ... 99,高位的0应该去掉;②此方法从0开始,题目要求从1开始;
- 解决①的方法:定义变量start来表示字符串的左边界,例如n = 2时,00 ~09时start = 1,10~99时start = 0;
- 那么start的变化规律是什么?现在我们来看两个示例:①n = 2时,00 ~09时start = 1,10~99时start = 0;②n = 3时,000~009时start = 2,010~099时start = 1,100~999时start = 0;
- 定义变量nineCount表示一个组合(比如009)中9的数量,通过示例可以发现:start = n - nineCount,也就是说当这个条件满足时,以n = 3为例,说明当前数为009,在到下一个010之前,将start--;
- 利用循环从高位向低位固定字符时,每固定一个高位字符,就要将nineCount回溯到固定之前的数值,因为每个高位字符之间是并列的关系;
- 解决问题②的方法:添加数字字符串的时候判断是否为"0",是就直接跳过。
class Solution {
char[] loop = {'0','1','2','3','4','5','6','7','8','9'};
char[] num;
int n;
int start;
int nineCount = 0;
StringBuilder res = new StringBuilder();
public String printNumbers(int n) {
this.n = n;
start = n - 1;
num = new char[n];
dfs(0);
res.deleteCharAt(res.length() - 1);
return res.toString();
}
//该方法的作用是固定当前位
public void dfs(int x) {
if(x == n) {
String s = String.valueOf(num).substring(start);
if(!s.equals("0")) res.append(s+",");
if(start == n - nineCount) start--;
return;
}
for(char i : loop) {
if(i == '9') nineCount++;
num[x] = i;
dfs(x + 1);
}
nineCount--;
}
public static void main(String[] args) {
Solution s = new Solution();
String str = s.printNumbers(2);
System.out.println(str);
}
}
3.4 打印从1到最大的n位数(返回int[])
- 因为题目要求是返回 int 数组,其默认不存在大数问题,但我们用大数的方法完全可以解决非大数的问题;
- 可以在添加数字字符串s之前,将其转换为int类型;
class Solution {
char[] loop = {'0','1','2','3','4','5','6','7','8','9'};
char[] num;
int n;
int start;
int count = 0;
int nineCount = 0;
int[] res;
public int[] printNumbers(int n) {
this.n = n;
start = n - 1;
num = new char[n];
res = new int[(int) (Math.pow(10, n) - 1)];
dfs(0);
return res;
}
//该方法的作用是固定当前位
public void dfs(int x) {
if(x == n) {
String s = String.valueOf(num).substring(start);
if(!s.equals("0")) res[count++] = Integer.parseInt(s);
if(start == n - nineCount) start--;
return;
}
for(char i : loop) {
if(i == '9') nineCount++;
num[x] = i;
dfs(x + 1);
}
nineCount--;
}
public static void main(String[] args) {
Solution s = new Solution();
int[] arr = s.printNumbers(2);
for(int i : arr) {
System.out.println(i);
}
}
}
四、学习地址
作者:Krahets