【大数问题】剑指 17 打印从1到最大的n位数

65 篇文章 1 订阅

剑指 17 打印从1到最大的n位数

原题目

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

示例 1:

输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]

力扣额外要求:

  • 用返回一个整数列表来代替打印
  • n 为正整数

考查知识点

字符串表示大数,递归


自己的第一遍解法

直接思路如下:

  1. 根据n获得对应的最大十进制数n_max
  2. 使用循环将1~n_max存入容器

首先来观察一下nn_max的对应关系:

n     n_max
1  ->  9
2  ->  99=90+9  
3  ->  999=900+90+9
4  ->  9999=9000+900+90+9 

nn_max的映射规律很明显,假设用f(n)表示n对应的n_max的话,有如下递推公式:

f(n) = 9*10^(n-1) + f(n-1)

有了递推公式,使用递归来寻找n_max就比较形象直接了,代码如下:

//先找到数字n对应的的最大数字,再遍历打印
class Solution {
public:
    vector<int> printNumbers(int n) {
        if (n < 1) return vector<int> {-1};
        int nmax = getNMax(n);      //获取数字n对应的最大数字
        vector<int> res;
        for(int i=1; i<=nmax; ++i)
            res.push_back(i);

        return res;
    }

    //求数字n对应的最大数字,1->9, 2->99, 3->999 ...递归实现:f(n) = 10^(n-1) + f(n-1)
    int getNMax(int n)
    {
        if (n == 1) return 9;

        int nMax = 0;
        nMax =9*pow(10.0, double(n-1)) + getNMax(n-1);

        return int(nMax);
    }
};

值得注意的是乘方函数pow(double x, double n)要求传入的底数x指数n都必须为double类型,返回值也是double类型(所以必须做强制类型转换),包含在头文件中。


好的解法

在没有限制n的大小时,要考虑大数问题,如果n对应的n_max非常大,超过int甚至long long的最大数值,那么就必须考虑使用字符串或数组来存储。注释得很清楚了。

//使用字符串存储数字,字符串顺序与数字顺序一致
 class Solution_jz {
 public:
     void Print1ToMaxOfNDigits(int n) {
         if (n<=0)   return;

         char *number =new char[n+1];
         memset(number, '0', n);
         number[n] = '\0';

         while (!Increment(number))
             PrintNumber(number);

         delete [] number;
     }

     //将用字符串表示的数字+1
    bool Increment(char *number)
    {
         bool isOverflow = false;       //第一个字符(即数字最高位)产生进位的标志,为真时表示不能再+1
         int nTakeOver = 0;     //进位
         int nLength = strlen(number);
         //从数字最低位开始+1计算进位
         for (int i=nLength-1; i>=0; --i)
         {
             //当前位数字与进位求和
             int nSum = number[i] - '0' + nTakeOver;
             //数字最低位+1
             if (i == nLength-1)
                 nSum++;
             //当前位产生进位
             if(nSum >= 10)
             {
                 if (i==0)
                     isOverflow = true;
                 else
                 {
                     nSum -= 10;
                     nTakeOver = 1;
                     number[i] = '0' + nSum;
                 }
             }
             //当前位无进位
             else
             {
                 number[i] = '0' + nSum;
                 break;
             }
         }

        return isOverflow;
    }

    //打印字符串表示的数字
    void PrintNumber(char *number)
    {
         bool isBeginning0 = true;
         int nLength = strlen(number);

         for(int i=0; i<nLength; ++i)
         {
             if (isBeginning0 && number[i]!='0')
                 isBeginning0 = false;

             if (!isBeginning0)
                 cout << number[i] << ' ';
         }
         cout << endl;
    }

 };

如果题目是针对n位整数,那么很有可能是考察大数问题,使用字符串表示数字时对某一位字符复制可以使用如下形式:使用字符串nums表示该大数,num是第i位数

nums[i] = '0' + num
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值