打印从1到最大的n位数
题目:输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
说明:
用返回一个整数列表来代替打印
n 为正整数
解题思路
首先我们可以看出当n为1时,输出最大为9;当n为2时,输出最大为99;当n为3时,输出最大为999;以此类推,我们可以得知输入n时,输出最大数为(10^n)-1;
当 n较大时,输出最大值会超出 int32整型的取值范围,超出取值范围的数字无法正常存储。不过题目函数的返回值是int类型,所以是默认不考虑大数问题的,因此我们只需用for循环就能轻松AC本题。
代码如下:
class Solution {
public:
vector<int> printNumbers(int n) {
vector<int>v;
for(int i=1;i<pow(10,n);i++)
{
v.push_back(i);
}
return v;
}
};
执行用时:12 ms, 在所有 C++ 提交中击败了71.28%的用户
内存消耗:11.1 MB, 在所有 C++ 提交中击败了54.27%的用户
难度升级
当要考虑大数问题时,这道题的难度就陡升了几个等级,绝对不是简简单单的for循环就能解决问题的。下面来学习一下力扣大佬是如何在考虑大数问题的前提下精彩的AC的。
- 首先要考虑到当n很大的时候(比如100),打印出来的数很有可能是超过了INT_MAX的范围的,所以我们用字符串来表示每个数。
- 当然,在这一题中,由于返回的是一个 int 型的数组,所以是不可能超过INT_MAX的,但是一般大数问题都不会要求返回 int 数组来保存每一位数,而是循环输出每一位数。
- 我们的思路就是,假设 n = 3,就定义一个字符串,初始化为 “000”,然后用它来循环模拟从1到最大的n位数,并循环保存到 int 数组中(在真实情况下则是循环输出)。
知识点扩展:char与int之间的加减法(比如 1 + ‘0’ 和 ‘1’ - ‘0’)
首先我们看一下ASCII表,会发现红框部分是int型[0, 9]的char值[48, 57],它们是连在一起的。
- 所以,如果我们用一个char与一个int相加,我们会得到一个char。比如:‘0’ + 1 = 48 + 1 = 49 = ‘1’。
- 如果我们用一个char减去另一个char,我们会得到一个int。比如:‘2’ - ‘0’ = 50 - 48 = 2。
- 所以,如果我们想把一个int型的数(比如 i = 5)转成char型,我们可以写成:char c = i + ‘0’;。
- 如果我们想把一个char型的数(比如 c = ‘5’)转成int型,我们可以写成:int i = c - ‘0’。
代码如下:
class Solution {
public:
vector<int> output;
vector<int> printNumbers(int n) {
// 以下注释的前提:假设 n = 3
if(n <= 0) return vector<int>(0);
string s(n, '0'); // s最大会等于999,即s的长度为n
while(!overflow(s)) inputNumbers(s);
return output;
}
bool overflow(string& s)
{
// 本函数用于模拟数字的累加过程,并判断是否越界(即 999 + 1 = 1000,就是越界情况)
bool isOverFlow = false;
int carry = 0; // carry表示进位
for(int i=s.length()-1; i>=0; --i)
{
int current = s[i] - '0' + carry; // current表示当前这次的操作
if(i == s.length() - 1) current ++; // 如果i此时在个位,current执行 +1 操作
if(current >= 10)
{
// 假如i已经在最大的那一位了,而current++之后>=10,说明循环到头了,即999 + 1 = 1000
if(i == 0) isOverFlow = true;
else
{
// 只是普通进位,比如current从9变成10
carry = 1;
s[i] = current - 10 + '0';
}
}
else
{
// 如果没有进位,更新s[i]的值,然后直接跳出循环,这样就可以回去执行inputNumbers函数了,即往output里添加元素
s[i] = current + '0';
break;
}
}
return isOverFlow;
}
void inputNumbers(string s)
{
// 本函数用于循环往output中添加符合传统阅读习惯的元素。比如001,我们会添加1而不是001。
bool isUnwantedZero = true; // 判断是否是不需要添加的0,比如001前面的两个0
string temp = "";
for(int i=0; i<s.length(); ++i)
{
if(isUnwantedZero && s[i] != '0') isUnwantedZero = false;
if(!isUnwantedZero) temp += s[i];
}
output.push_back(stoi(temp));
}
};
链接:https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/solution/fei-zi-jie-ti-ku-jian-17-jian-dan-da-yin-cong-1dao/
总结
当考虑了大数为前提后,说实话这道题是真的难,看完大佬的解法后还是有点懵的,不知道他们是如何想出这种解法的,膜拜一下大佬。同时感觉自己和大佬的差距不是一点半点啊,革命尚未成功,同志仍需努力!!!mark一下这道题的解法,二刷的时候还得重新好好理解一下,看看到时候能秒掉它。大家共勉吧!!!