剑指offer -- 打印从1到最大的位数(大数表达 字符串模拟数字加法)

题目:
给你一个正整数n 请实现函数输出 1~n 位数的最大数。比如n=5,输出1,2,3,4,5 … … 99,100 … … 99999。
我们很容易想到的方法就是先算出这个n位数的最大数, 然后再循环输出好了 。但是你转念又一想,如果n是一个很大的数,那么我们求出的n位最大数 用 int 还是 longlong 是不是都会溢出。这个问题需要我们最主要解决的就是大数问题。
我们一般可以用字符串来表达大数,一共最多 n位数,我们申请一个n+1长度的char类型数组 ,全部赋初值为 0。 然后每一次为字符串加1,在打印出来。所以我们最主要做的就是两件事 ,一是在字符串表达上模拟数字加法, 二是把字符串以数字的形式输出出来。

模拟数字加法:
我们从最后一位数开始分析 我们每次加1 打印 1 2 3直到最后一位数到9,在加1变成10。那么字符串的倒数第二位就变成了1,我们下一次输出是11,又回到了最后1位而倒数第二位的1是不变的。直到最后一位的9又变成了10,倒数第二位再加1变成了2 ,下一次输出又回到了倒数第一位。当倒数第二位的数字变成9 ,倒数第一位的数字也变成了9 加1变成了10, 那么倒数第二位进位也变成了10,即倒数第三位应该变成了1,然后又回到了最后一位开始加1,慢慢又进位。每次进位完成后都会又会回到最后一位开始继续加1输出下一个数字。那么什么时候结束呢 当第一位数字 (i= 0的位置) 需要进位 从9变成10时 结束打印。

输出:
而我们输出的时候也不能是简单的用库函数输出,因为我们的字符串前面还有一堆我们用来填补空位的0,是不能输出的 ,输出的时候找到第一个非零字符开始打印。

#include<iostream>
using namespace std;
bool Increment(char *number);
void PrintfNumber(char *number);

void PrintfToMaxOfNDigits(int n)
{
    
    
	if(n<=0) return;

	char *number = new char[n+1];
	memset(number,'0',n);
	number[n] = '\0';  //字符串最后一位为'\0

	while(!Increment(number)){
    
     //进入模拟数字加法函数
		PrintfNumber(number);  //打印函数 模拟加法函数 返回false 才会打印 
	}
	delete []number;
}
bool Increment(char *number){
    
    
	bool isOverflow = false;  //记录是否是第一位产生的进位初始值为false
	int nTakeOver = 0; 
	int nLength  = strlen(number);
	for(int i = nLength - 1;i >= 0;i--){
    
      //如果发生进位那么就会往前走 假如现在字符串为99 进入循环是最后一位9+1=10了 需要进位 最后一位变成0
		int nSum = number[i] - '0' + nTakeOver;  //nTakerOver=1 i-- 往前走 到了倒数第二位 因为是倒数第二位 只涉及到进位的加1 数字的加1都是需要从最后一位加的
		if(i == nLength-1)              //而倒数第二位现在也为9  因为进位加1变成了10 则倒数第二位变成了0  又i--到下一次循环的倒数第三位 第三位的数字只有一位
			                             //进位加的 1 则当前字符串变成了100 下一次加1 又从最后一位开始进行 即如果加1不造成最后一位的进位 则不会再次进入循环
											 //直接打印 但是如果造成进位 还会接连造成前面的进位 那么把发生进位的位置变为0,然后移动到相应的位置进行进位加1的计算
			nSum++;

		if(nSum >= 10){
    
     
			if(i == 0)    //产生了进位 如果是第一位产生的进位则 标志置为true 结束打印
				isOverflow = true;
			else
			{
    
    
				nSum = nSum - 10;  //产生了进位 最后一位变成了0 
				nTakeOver = 1; //用来表示发生进位 这个数位的前一位应该加1
				number[i] = '0' + nSum;  //该位发生进位变成0  

			}
		} 
		else
		{
    
    
			number[i] = '0' + nSum;
			break;
		}
	}
	return isOverflow;
}

void PrintfNumber(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)
		{
    
    
			printf("%c",number[i]);
		}
	}
	printf("\t");
}
int main()
{
    
    
	
	int n=3;
	PrintfToMaxOfNDigits(n);
	return 0;
}

如果有的小伙伴的编译器可以行断点调试,那你可以进行调试走一下进位的过程更方便你理解,会比看别人说理解的更深刻。

猜你喜欢

转载自blog.csdn.net/scarificed/article/details/120344261