面试题17:打印1到最大的n位数

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

知识点

char与int之间的加减法(比如 1 + ‘0’ 和 ‘1’ - ‘0’)
在这里插入图片描述

字符串解决大数问题

最常用也是最容易的方法便是使用字符串或者数组来表示大数。接下来我们用字符串来解决上述问题。

用字符串表示很大的整数时,一个很直观的方法便是字符串的每一位都用‘0’~‘9’的字符来填充,用以表示大数的某一位。由于题目要求有n位数,那么我们需要的字符串长度为n+1(字符串最后一位是结束符‘\0’)。当实际数字不够n位时,前面的部分用‘0’填充。

这样转化以后,还有两个关键的问题需要解决。一是如何用字符串模拟整数的自增1运算,二是如何打印出来以符合我们日常书写整数的习惯(即数字前面的0不打印)。

要提前说明的一点:在C++中,字符的‘+’‘-’等运算实质上是ASC码进行相应运算。

先说说如何用字符串模拟整数的自增1运算:其实很简单,我们只需要从字符串的最后一位开始自增1(利用上述说明的一点即可),同时需要利用一个变量记录进位。那么何时自增结束呢(即达到最大的999……999,n个9):显然,仅当999……999(n个9)在其基础上自增1的时候,才会在字符串第一位产生进位。我们可以利用这个条件来判断自增结束,这样可以在O(1)的时间内进行判断。

接下来便考虑如何打印:其实有了字符串每一位初始化为‘0’的前提之后,我们打印时只需要从遇到的第一个非‘0’符开始打印即可。

  • 不考虑大数问题解法
#elif 0//不考虑大数解法
class Solution {
public:
    vector<int> printNumbers(int n) {
        vector<int> res;
        if (n <= 0)
            return res;
        int num = pow(10,n);
        for(int i = 1; i <num;++i)
            res.push_back(i);
        return res;
    }
};
#endif
  • 通过使用char数组进行求解大数问题
#if 1
class Solution {
public:
	vector<int> res;
	vector<int> printNumbers(int n) {
		if (n <= 0) return res;
		//创建一个能容纳最大值的字符数组,由于有一位要存储'\0',因此要开大一格
		char* number = new char[n + 1];
		memset(number, '0', n);//初始全部设置为0
		number[n] = '\0';//第n位设为'\0'
		while (!Increment(number)){
			PrintNumber(number);
		}
		delete[]number;//注意要释放内存
		return res;
	}

	bool Increment(char* number) {//形参传递char*指针
		bool isOverflow = false;//检测是否越界
		int nTakeOver = 0;//存储进位
		int nLength = strlen(number);//长度为n,不是n+1
		
        for (int i = nLength - 1; i >= 0; i--){
			int nSum = number[i] - '0' + nTakeOver;//首先将字符转化为int型数字			
            if (i == nLength - 1)//如果是第一位,加1(循环变量)
				nSum++;        
			            
            if (nSum >= 10){ //有进位
				if (i == 0)//如果是最高位有进位,说明超过了给定得到最大值,越界	
					isOverflow = true;
				else{//非最高位有进位
					nTakeOver = 1;
					number[i] = nSum - 10 + '0';//对第i位进行设置
				}
			}

			else{//没有进位;设置第i位数字;并直接跳出循环
				number[i] = nSum + '0';
				break;
			}
		}
		return isOverflow;
	}
	
    
    void PrintNumber(char* number)	{
	//形参传递char*指针,此处改变形参number指向的位置,不会使原始的number指针所指位置改变
		string s = "";
		bool isBegin0 = true;
		while (*number != '\0')
		{
			if (isBegin0 && *number != '0') 
                isBegin0 = false;
			if (!isBegin0)//碰到'0',则不输出
			{
				s += *number;
			}
			number++;
		}
		int num = stoi(s);//转为整数
		res.push_back(num);
	}
};

  • 通过使用string进行求解大数问题
class Solution {
public:
    vector<int> res;
    vector<int> printNumbers(int n) {
        if (n <= 0) return res;
        string number(n,'0');//创建一个能容纳最大值的字符数组
        while (!Increment(number)) {//初始全部设置为0
            saveNumber(number);
        }
        return res;
    }
    
    bool Increment(string& number) {//注意要使用引用传递,否则无法修改number
        bool isOverFlow = false;//检测是否越界
        int nTakeOver = 0;//存储进位
        int nLength = number.size();
        for (int i = nLength - 1; i >= 0; i--){
            int nSum = number[i] - '0' + nTakeOver;
            if (i == nLength - 1)
                nSum++;
            
             if(nSum >= 10){
                if(i == 0)
                    isOverFlow = true;
                else{
                    nTakeOver = 1;
                    number[i] = nSum - 10 + '0';//int 转char
                }
            }

            else{
                number[i] = nSum + '0';//int 转char
                break;//如果没有进位,不用继续循环计算高位数值,直接跳出循环
            }
        }
        return isOverFlow;
    }
    
    void saveNumber(string number) {//由于此处输出,不需要修改number,因此不需要加引用
        string s = "";
        bool isBegin0 = true;
        string::iterator it = number.begin();
        while (it != number.end()){
            if (isBegin0 && *it != '0') isBegin0 = false;
            if (!isBegin0){
                s += *it;
            }
            it++;
        }
        res.push_back(stoi(s));
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值