【题目描述】
求两个不超过200位的非负整数的和。
【输入】
有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。
【输出】
一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
【输入样例】
22222222222222222222
33333333333333333333
【输出样例】
55555555555555555555
说明:
主要考查高精度加法。
题目概述:
C++整型的最大值也不超过20位数字,而本题求两个不超过200位的加数相加之和。很明显,不能使用常规的方法直接求解。
题目提示《可能有多余的前导0》,说明输入的并不是整型数值,而是字符串。字符串中的每个字符其实就是char类型字符,而char类型其实也是一种整型,可以进行相加的操作。
所谓前导0,是在数字的最前面有1个及以上的0,例如数字123,但输入的时候可能是0123或000123。
所以,输入字符串,把字符串中的字符转换为整型一一相加,就能得出最终的结果。
思路分析:
如果有两个char数组a1和a2,输入的两个加数是:
那么有:
char a1 = "00123456789";
cahr a2 = "987654321";
很明显,一个加数有前导0。而且高位在左边,低位在右边。
转换为竖式,并把多余的前导0去掉:
如上图所示,如果直接使用竖式加法,算出结果不难。但要考虑是在两个char数组的基础上相加,而且有无前导0,有多少个前导0,哪个数组有前导0。
char数组也是一个字符串,此时不妨把字符串反过来,变成:
a1 = "98765432100";
a2 = "123456789";
很明显,从左往右就是从低位到高位。如果不翻转,两个加数的个位可能不对齐。现在数字经过翻转后,不需要考虑个位是否对齐的问题,而且对于高位的前导0也无需考虑,因为char类型的字符串是以空字符'\0'结尾,只要遇到空字符,结束运算即可。
同时,还要考虑进位问题,例如15+16=31,5+6=11,要进位。因为个位数字相加时,不需要加上进位值,所以可以声明一个int类型变量z = 0作为进位值。从十位数字开始,加上进位值,如果相加大于9,也要进位。
如上图的例子,个位9+1=10,所以个位为0,进位变量为1。十位8+2=10,但要加上由个位进位的1,所以是11,而11>9,也要进位。
以上便是解题的主要思路,其实就是竖式加法,只不过现在是应用在编程中。其次,还要考虑细节问题。例如需不需要翻转字符串,是否删除前导0,是否把char数组转换为int数组等等。
解决本题的不止有一种方法,其核心还是运用竖式加法。为了让大家能学习更多的知识以及了解更多的技巧,本题解将把多个细节都一一列举,即处理翻转char数组,去除前导0,以char类型进行加法运算(即不转换为int数组)。
数据类型:输入的加数都是字符串类型,可选string或char数组。
重难点:
本题难度不大,注意有前导0的情况。
解决本题的关键是输入的加数以字符串的形式输入,相加时注意进位。其他细节可以灵活变通,例如是否需要翻转字符串,对前导0如何处理,选择string还是char数组等等。
求解过程:
声明2个char类型数组a1[202] = {0}和a2[202] = {0},分别表示两个加数。
输入两个加数。
声明1个int类型数组a3[203] = {0},用于存储两个加数之和。
声明4个int类型变量t、x = 0、y = 0、z = 0,t用于交换数据,x用于记录第一个加数个位数字的下标,y用于记录第二个加数个位数字的下标,z用于存储进位值。
声明2个int类型变量n1和n2,n1用于获取数组a1的实际长度,n2用于获取数组a2的实际长度。使用库的strlen函数可获取char数组的实际长度(不包括空字符)。
循环获取第一个加数个位数字的下标,while(a1[x] && a1[x+1]),循环体中:
1.如果a1[x]等于字符'0',则x加1。
2.否则,退出循环。
循环获取第二个加数个位数字的下标,while(a2[y] && a2[y+1]),循环体中:
1.如果a2[y]等于字符'0',则y加1。
2.否则,退出循环。
上述两个循环可以获取前导0的长度,实际上也是个位数字的下标。
使用循环翻转字符数组a1和a2,使其个位数在前,翻转时,前导0不动,只翻转真实数字。
使用循环开始相加,并把运算的结果存储在数组a3中,把进位值存储在变量z中。
判断进位变量z是否为1,如果为1,表示继续进位,数组a3的实际长度也要加1。
循环输出最终的结果,即数组a3。
运行结果:
参考代码 - C++:
除此之外,还要考虑加数为0的情况。代码中的48其实是字符'0'的ASCII码,这是一个基础知识,必须要掌握。
代码中运用了一些小技巧,例如逗号表达式、在数组中运用自加运算符、条件运算符等,能体现C++的灵活性。作为初学者在理解上可能有点难度,不过对于初学算法的同学来说,何尝不是一个锻炼的机会。
#include
#include
using namespace std;
int main(){
char a1[202] = {0}, a2[202] = {0};
cin >> a1 >> a2;
int a3[203] = {0}, t, x = 0, y = 0, z = 0;
int n1 = strlen(a1), n2 = strlen(a2);
while (a1[x] && a1[x + 1]) // 获取个位数字的下标
{
if (a1[x] == 48) x++;
else break;
}
while (a2[y] && a2[y + 1])
{
if (a2[y] == 48) y++;
else break;
}
// 把整数翻转过来,即个位数在前
for (int i = x, k = 0, m = (n1 - x + 1) / 2 + x; i t = a1[i], a1[i] = a1[n1 - 1 - k], a1[n1 - 1 - k++] = t;
for (int j = y, k = 0, m = (n2 - y + 1) / 2 + y; j t = a2[j], a2[j] = a2[n2 - 1 - k], a2[n2 - 1 - k++] = t;
n1 -= x; // 减去前导0的数目,才是真实的长度
n2 -= y;
if (n1 // 获取最大整数的长度
for (int k = 0; k // 开始相加求和
{
a3[k] = (a1[x] ? a1[x] - 48 : 0) + (a2[y] ? a2[y] - 48 : 0) + z;
if (a3[k] >= 10) z = 1, a3[k] -= 10; // 判断相加后是否进位
else z = 0;
}
if (z) a3[n1++]++; // 如果进位值不为0,说明最高位要进位
for (int i = n1 - 1; i >= 0; i--) cout < return 0;
}
END
注:题目来源于网络,转载于《信息学奥赛一本通(C++版)在线评测系统》,点击下方的【阅读原文】即可打开该题的链接。
题解属于本微信公众号【大神编程】原创。