【引入】
在现实中,当对两个超级大的整数进行加法运算的时候,这两个超级大的数以及它们的结果都是没办法用变量存起来的。但是我们可以用数组或者字符串去存储,然后在这基础上进行运算。
数组 + 整数
【题目描述】
对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]。
给定非负整数 X 的数组形式 A,返回整数 X+K 的数组形式。
题目来源(力扣):数组形式的整数加法
解法一
基本思路: 就是加法的竖式计算,逐位相加,满十进一。这个解法把进位单独用变量存起来。
注:a + b = c(假设 a 是M位数,b 是N位数,且M > N),c 是 M 位数或 M + 1位数,也就是说 c 最多是 M + 1 位数。
比如 999 + 999 = 1998 , 1998是四位数。
void reverseArray(int* num, int numSize)
{
int left = 0, right = numSize - 1;
while (left < right)
{
int tmp = num[left];
num[left] = num[right];
num[right] = tmp;
left++;
right--;
}
}
int* addToArrayForm(int* num, int numSize, int k, int* returnSize) {
int kSize = 0;
int kNum = k;
while (kNum)
{
kSize++;
kNum /= 10;
} //上面的代码是为了计算出 k 是几位数
int maxlen = numSize > kSize ? numSize : kSize;
int* retArr = (int*)malloc(sizeof(int)*(maxlen + 1));
int reti = 0;
int numi = numSize - 1;
int nextNum = 0; //进位
while (maxlen--)
{
/*int sum = (num[numi] + k % 10 + nextNum) % 10;
nextNum = (num[numi] + k % 10 + nextNum) / 10;
numi--;*/
**********************
int a = 0;
if (numi >= 0)
{
a = num[numi]; //下面有说明
numi--;
}
int sum = (a + k % 10 + nextNum) % 10;
nextNum = (a + k % 10 + nextNum) / 10;
**********************
k /= 10;
retArr[reti++] = sum;
}
if (nextNum == 1) //上面的循环走完了,还存在着进位。比如:99 + 62 = 161
{
retArr[reti++] = 1;
}
reverseArray(retArr, reti);
*returnSize = reti;
return retArr;
}
说明:while (k–) 是循环 k 次 。
而 while (–k) 是循环 k - 1 次。
在这里我们希望它循环 k 次,因而使用 while (k–) 来控制。
说明:不能写成/**/之间的,要写成 “ ******* ”之间的。原因:当 k 的位数比 num[] 的位数更大时,会出现数组越界访问。
由于我们把每位相加的结果倒着放进了数组,因此需要把数组逆置一下。
我们在刷题的时候不能只盯着给出来的示例,它给的示例一般都是比较常规的,更多的时候还是要去考虑没那么常规的情况。
注:在这里,我们当中可能有的人不明白为什么要给参数 int* returnSize,不知道是干嘛用的。
其实,当函数返回一个 int* 指针时,如果代表一个数组的话,函数一般都会有参数 int* returnSize。
在调用这个函数时,会给变量(在这里我假设变量名是 size )的地址作为参数传进去,函数执行完之后,size 的值应该是函数返回的数组的大小。
你想吗,如果没有 int* returnSize 这个参数,那么函数返回的数组的大小你是不知道的,于是访问这个数组的元素时很有可能越界。(说准确一点,连数组的界在哪都不知道)
解法二
这个解法把进位加到了整数 k 上。
int* addToArrayForm(int* num, int numSize, int k, int* returnSize) {
int kSize = 0;
int kNum = k;
while (kNum) //计算k是几位数
{
kSize++;
kNum /= 10;
}
int maxlen = numSize > kSize ? numSize : kSize;
int* retArr = (int*)malloc(sizeof(int)*(maxlen + 1));
int reti = 0;
for(int i = numSize - 1; i >=0; i--)
{
int sum = num[i] + k % 10;
k /= 10;
if(sum > 9)
{
k++;
sum -= 10;
}
retArr[reti++] = sum;
}
while(k) //下面有说明
{
retArr[reti++] = k % 10;
k /= 10;
}
reverseArray(retArr, reti);
*returnSize = reti;
return retArr;
}
说明:为了应对 k 的位数比 num[] 的位数大的情况,写了最后的while循环。把多出来的 k 的前面的那几位数直接拷到数组。
数组 + 数组
整体思路还是跟上面的 解法一 是一样的,只是都以数组的形式相加。
void reverseArray(int* num, int numSize)
{
int left = 0, right = numSize - 1;
while (left < right)
{
int tmp = num[left];
num[left] = num[right];
num[right] = tmp;
left++;
right--;
}
}
int* addArrays(int* num1, int num1Size, int* num2, int num2Size, int* returnSize)
{
int maxlen = num1Size > num2Size ? num1Size : num2Size;
int* retArr = (int*)malloc(sizeof(int)*(maxlen + 1));
int reti = 0;
int num1i = num1Size - 1, num2i = num2Size - 1;
int nextNum = 0; //进位
while (maxlen--)
{
int a = 0;
if (num1i >= 0)
{
a = num1[num1i];
num1i--;
}
int b = 0;
if (num2i >= 0)
{
b = num2[num2i];
num2i--;
}
int sum = (a + b + nextNum) % 10;
nextNum = (a + b + nextNum) / 10;
retArr[reti++] = sum;
}
if (nextNum == 1)
{
retArr[reti++] = 1;
}
reverseArray(retArr, reti);
*returnSize = reti;
return retArr;
}
字符串 + 字符串
这里要先知道这么一个点,就是字符型数字怎么转换为整型数字。
‘9’ - ‘0’ == 9
只需把字符型数字减去字符0即可,它们的ASCII码的差值就是我们想要的结果。
【题目描述】
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。
题目来源(力扣):字符串相加
void reverseString(char* str, int len)
{
int left = 0, right = len - 1;
while (left < right)
{
char tmp = str[left];
str[left] = str[right];
str[right] = tmp;
left++;
right--;
}
}
char * addStrings(char * num1, char * num2) {
int maxlen = strlen(num1) > strlen(num2) ? strlen(num1) : strlen(num2);
char* retStr = (char*)malloc(sizeof(char)*(maxlen + 2));
//因为这是一个字符串,后面还要放'\0',所以不是 maxlen + 1,而是 maxlen + 2
int reti = 0;
int num1i = strlen(num1) - 1;
int num2i = strlen(num2) - 1;
int nextNum = 0;
while (maxlen--)
{
char m = '0';
if (num1i >= 0)
{
m = num1[num1i];
num1i--;
}
char n = '0';
if (num2i >= 0)
{
n = num2[num2i];
num2i--;
}
int sum = ((m - '0') + (n - '0') + nextNum) % 10;
nextNum = ((m - '0') + (n - '0') + nextNum) / 10;
retStr[reti++] = '0' + sum;
}
if (nextNum == 1)
{
retStr[reti++] = '1';
}
retStr[reti] = '\0';
reverseString(retStr, strlen(retStr));
return retStr;
}
因为我们要进行 % 和 / 的运算,用字符型数字是不能达到要求的,因为字符型数字的运算实质上是ASCII码的运算,并且字符型数字的ASCII码与字符型数字不是绝对对应起来的(比如 ‘0’ 的ASCII码是 48 ,而不是 0 )。