数组形式的整数加法(详解)
题目:
整数的 数组形式 num
是按照从左到右的顺序表示其数字的数组。
- 例如,对于
num = 1321
,数组形式是[1,3,2,1]
。
给定 num
,整数的 数组形式 ,和整数 k
,返回 整数 num + k
的 数组形式 。
示例 1:
输入:num = [1,2,0,0], k = 34
输出:[1,2,3,4]
解释:1200 + 34 = 1234
示例 2:
输入:num = [2,7,4], k = 181
输出:[4,5,5]
解释:274 + 181 = 455
示例 3:
输入:num = [2,1,5], k = 806
输出:[1,0,2,1]
解释:215 + 806 = 1021
注意:
对于这道题目来说,不可采用,将数组里的数拿出来去x10,x100,x1000这样子去做,因为当数组大道一定正度的时候,int类型无法存放太大的数,即便用long long 类型也不行
这题实际上想考的是——大数相加
分析:
其实这道题目就是用我们之前小学的加法来做就行了。
如图所示:
先看第一位:4 + 1 = 5
在看第二位:7 + 8 = 15 大于10 进1
第三位: 2 + 1 = 3 再+ 第二位进的1 = 4
所以就是 455。
思路:
- 首先我们要知道两个相加的数的位数
- 对于数组来说,位数就是数组的长度 也就是numsize
- 对于k数字来说,位数需要我们自己去算
- 知道了位数之后,我们就需要给新数组申请内存空间
- 空间的大小是两个数的最大位数 + 1 (n位数相加可能是n位数,也可能是n+ 1位数)
- 并且要相加多少次,也是取决于最大位数。
- 判断相加之后是否大于10,大于10要记得进1处理
- 由于我们不知道相加之后的数是否是n+1位数,因此采取下标0存储数据。
- 等到所有的位数相加完后,存到新数组之中后,再将数组进行逆序处理
代码:
int* addToArrayForm(int* num, int numSize, int k, int* returnSize)
{
// 要想进行相加 我们需要知道两个加数的位数 数组的位数就是numSize
// 那么我需要知道k是多少位的数字
int knum = k; // 让knum接受k的值 去进行操作 不然后面找不到k了
int kSize = 0; // kSize就是k这个数字的位数
while(knum)
{
kSize++;
knum/=10;
}
// 我们知道,每次相加都是位跟位之间的相加 比如个位加个位 十位加十位......
// 我们如果想知道要相加多少次 那就需要最大的加数的位数
int len = numSize < kSize ? kSize : numSize; // len此时就是最大的数的位数
// 知道了相加的次数 我们需要一个新的数组 来存放我们相加的值
// 由于这个数组的空间是不确定的,因此我们需要动态申请空间 (malloc)
int* retArr = (int*)malloc(sizeof(int) * (len + 1));
// len+1 是因为 n位数+n位数 可能是n位数 也可能是n + 1位数
int numnext = 0; // 用于记录位数相加是否需要进 1
int reti = 0; // 用于retArr新数组的下标记录
// 我们首先要进行个位数的相加,那我们得先将个位数取出来
int ni = numSize - 1; // 数组的最后一个元素就是 数组的个位数.
//numSize - 1 就是最后一个元素的下标, ni就是数组的个位数
//后面对ni - 1就可以取到十位,以此类推
// 有了新数组retArr 我们就要相加
while(len--) // 前面我们说了len就是最大位数,也就是相加的次数
{
int N = 0;
if(ni >= 0) // 如果数组的位数小于k的位数,那么后面的ni一定会小于0,就会造成越界访问
{
N = num[ni]; // 如果ni小于0 就说明这个地方的位数的值为0就好
}
// 对位数进行相加
int ret = N + k % 10 + numnext; // 如果有进位就加上进位,没有进位+0也不影响
// 这里要注意ni是否越界的问题
k /= 10; // 相加完之后 让k少去个位数 这样下一次k % 10 取得就是十位数 ,以此类推
ni--; // 这样ni指向的就是数组的下一位数
// 判断位数相加是否大于等于10
if(ret >= 10)
{
// 大于10 要在下一位相加的时候进1
numnext = 1;
ret -= 10;
}
else
{
numnext = 0; // 要置为0 不然如果numnext = 1 后面有位数相加 就会导致多进一个1
}
// 由于不清楚n位数加n位数 到底是n位数 还是n+1位数 这个下标不好从后面开始定位
// 因此这里采取从下标0开始存储,等相加完,存储完之后 在循环外面进行数组的逆序
retArr[reti] = ret;
reti++;
}
// 这里还有一个问题 如果数组和k的位数相同,都是n位数。那么如果 加起来是n+1位数,这个时候的n+1位就没有存下来
if(numnext == 1)
{
retArr[reti] = 1; // 给n+1位 一个进位 也就是1
reti++; // 记得要让reti++ 及时改变数组的长度,也就是元素个数,reti++之后的reti记载的是元素个数
}
// 对retArr进行逆序
int left = 0;
int right = reti - 1; // reti记载了我们结果的位数 right是该数组的最后一个元素的下标
while(left < right)
{
int temp = retArr[left];
retArr[left] = retArr[right];
retArr[right] = temp;
left++;
right--;
}
*returnSize = reti;
return retArr; // 注意了 返回这个数组的首元素地址,但是接口不知道你的数组长度
}
要注意的一些点:
- 首先就是位数相同的时候,比如n位数+n位数,如果是n+1位数,我们的循环是解决不了问题的
代码是这样解决的:
// 这里还有一个问题 如果数组和k的位数相同,都是n位数。那么如果 加起来是n+1位数,这个时候的n+1位就没有存下来
if(numnext == 1)
{
retArr[reti] = 1; // 给n+1位 一个进位 也就是1
reti++; // 记得要让reti++ 及时改变数组的长度,也就是元素个数,reti++之后的reti记载的是元素个数
}
- 如果是数组的位数小于k的位数的时候,数组会有越界访问的情况
如图所示:
我们的代码是这样解决的:
int N = 0;
if(ni >= 0) // 如果数组的位数小于k的位数,那么后面的ni一定会小于0,就会造成越界访问
{
N = num[ni]; // 如果ni小于0 就说明这个地方的位数的值为0就好
}
- 要记得返回我们的数组长度
题目中的函数形参中有给到int* returnSize。
*returnSize = reti;