打印从1到最大的n位数(C++简单区???)

打印从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的。

  1. 首先要考虑到当n很大的时候(比如100),打印出来的数很有可能是超过了INT_MAX的范围的,所以我们用字符串来表示每个数。
  2. 当然,在这一题中,由于返回的是一个 int 型的数组,所以是不可能超过INT_MAX的,但是一般大数问题都不会要求返回 int 数组来保存每一位数,而是循环输出每一位数。
  3. 我们的思路就是,假设 n = 3,就定义一个字符串,初始化为 “000”,然后用它来循环模拟从1到最大的n位数,并循环保存到 int 数组中(在真实情况下则是循环输出)。

知识点扩展:char与int之间的加减法(比如 1 + ‘0’ 和 ‘1’ - ‘0’)
首先我们看一下ASCII表,会发现红框部分是int型[0, 9]的char值[48, 57],它们是连在一起的。
在这里插入图片描述

  1. 所以,如果我们用一个char与一个int相加,我们会得到一个char。比如:‘0’ + 1 = 48 + 1 = 49 = ‘1’。
  2. 如果我们用一个char减去另一个char,我们会得到一个int。比如:‘2’ - ‘0’ = 50 - 48 = 2。
  3. 所以,如果我们想把一个int型的数(比如 i = 5)转成char型,我们可以写成:char c = i + ‘0’;。
  4. 如果我们想把一个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一下这道题的解法,二刷的时候还得重新好好理解一下,看看到时候能秒掉它。大家共勉吧!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值