题目
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
说明:
- 用返回一个整数列表来代替打印
- n 为正整数
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof
解题思路
不考虑大数版本情况下很简单,其实就是依次打印1 ~ 10n - 1
主要考虑的还是大数越界情况下的打印
- 使用字符串表示数值
- 每一位都是0 ~ 9字符的全排列
- 怎么消除全排列前面无意义的0
- 从1开始打印,0不要
以n = 3为例
主要难点就是消除全排列前面无意义的0,
9,99,999…的时候,都需要进位,所以主要还是看字符中9的个数
假设左边界为start,初始化时start = n - 1,因为数组长度为n时,最后一位下标为n - 1
假设字符数组中’9’的个数为nine,初始化时为0,每一次循环碰到’9’就进行加一,循环结束减一
当字符数组为9,99,999时nine为1,2,3,此时start分别为2,1,0,则有n - start = nine
代码
不考虑大数
class Solution {
public int[] printNumbers(int n) {
// 10的次方减一
int num = (int)Math.pow(10, n) - 1;
// 1 ~ num就是num个空间
int[] array = new int[num];
for (int i = 0; i < num; i++) {
array[i] = i + 1;
}
return array;
}
}
- 时间复杂度:O(10n),生成长度为 10n的列表需使用 O(10n)时间
- 空间复杂度:O(1),建立列表使用O(1)大小的额外空间,列表作为返回结果,不计入额外空间
考虑大数,返回字符串
class Solution {
// 全排列使用到的字符数组
private char[] cArr = {'0','1','2','3','4','5','6','7','8','9'};
// 用来存储元素
private LinkedList<String> tempList;
// 字符数组,用来存储全排列的字符串
private char[] numArr;
// 左边界值,用来消除前面的0
private int start;
// 用来记录9的个数,9,99,999的时候需要start--
private int nine;
public String printNumbers(int n) {
// 考虑大数版本
// 初始化
tempList = new LinkedList<>();
numArr = new char[n];
// 初始化左边界为n - 1,即从字符数组的最后一个下标开始
start = n - 1;
nine = 0;
dfs(0, n);
// 删除第一个元素,因为从1开始,删除0
tempList.removeFirst();
return String.join(",", tempList);
}
private void dfs(int index, int n) {
// 递归结束条件,字符数组下标越界
if (index == n) {
// 字符数组转字符串
String s = new String(numArr).substring(start);
tempList.add(s);
// 当所有位都为9的时候,左边界值减一
if (n - start == nine) {
start--;
}
return;
}
// 迭代字符数组
for (char c : cArr) {
// 当前字符为9时,计数器加一
if (c == '9') {
nine++;
}
// 赋值当前下标
numArr[index] = c;
// 递归调用
dfs(index + 1, n);
}
// 撤销计数器
nine--;
}
}
- 时间复杂度:O(10n),生成长度为 10n的列表需使用 O(10n)时间
- 空间复杂度:O(10n),使用列表的长度10n - 1
考虑大数,返回int数组
class Solution {
// 全排列使用到的字符数组
private char[] cArr = {'0','1','2','3','4','5','6','7','8','9'};
// 字符数组,用来存储全排列的字符串
private char[] numArr;
// 返回的数组
private int[] array;
// 左边界值,用来消除前面的0
private int start;
// 用来记录9的个数,9,99,999的时候需要start--
private int nine;
// 数组下标
private int count;
public int[] printNumbers(int n) {
// 考虑大数版本
// 初始化
int num = (int)Math.pow(10, n) - 1;
array = new int[num];
numArr = new char[n];
// 初始化左边界为n - 1,即从字符数组的最后一个下标开始
start = n - 1;
nine = 0;
count = 0;
dfs(0, n);
return array;
}
private void dfs(int index, int n) {
// 递归结束条件,字符数组下标越界
if (index == n) {
// 字符数组转字符串
String s = new String(numArr).substring(start);
if (!s.equals("0")) {
array[count++] = Integer.parseInt(s);
}
// 当所有位都为9的时候,左边界值减一
if (n - start == nine) {
start--;
}
return;
}
// 迭代字符数组
for (char c : cArr) {
// 当前字符为9时,计数器加一
if (c == '9') {
nine++;
}
// 赋值当前下标
numArr[index] = c;
// 递归调用
dfs(index + 1, n);
}
// 撤销计数器
nine--;
}
}
- 时间复杂度:O(10n),生成长度为 10n的列表需使用 O(10n)时间
- 空间复杂度:O(1),建立列表使用O(1)大小的额外空间,列表作为返回结果,不计入额外空间