给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入:digits = [1,2,3] 输出:[1,2,4] 解释:输入数组表示数字 123。示例 2:
输入:digits = [4,3,2,1] 输出:[4,3,2,2] 解释:输入数组表示数字 4321。示例 3:
输入:digits = [0] 输出:[1]提示:
1 <= <= 100
0 <= digits[i] <= 9
思路讲解
拿到这道题,这是个加法题,由于在数组中导致可能数组中的元素导致变化,然而每个数组存一个元素他不能像一个整型加减法一样你直接加一输出就行了,你得判断下一个字符会不会进一影响上一个字符,所以我们得一个一个判断数组中的元素,这是我们就能用到递归的思想,构造一个递归函数可以不断判断数组中的每一个元素是否加一后会影响上一位。
我们首先先写题目要求我们写的plusOne函数,个人习惯通过主函数知道我们我们需要哪些信息从而更好地写构造函数达成目标,在我们写主函数的过程中也能使我们对需要写的递归函数有一个大致的轮廓框架。
先看题目中主函数给我们的参数
int* plusOne(int* digits,int digitsSize,int* returnSize)
{
}
我们先考虑不同情况,从简单的入手
情况一
数组最后一位并不是9,加一后不用改变前面的其他任一元素,可以直接输出前面的所有元素加上最后一个元素加一。
if(digits[digitsSize-1]!=9)
{
}
由于题目要求The returned array must be malloced, assume caller calls free().所以我们一开始使用calloc来分配内存,确保所有位都初始化为0。
int* returnbuff=(int*)calloc(digitsSize,sizeof(int));
既然最后一位不是9,说明他不会进一,直接用加法得到个位的结果
digits[digitsSize-1]=digits[digitsSize-1]+1;
处理完个位,我们还要输出前面所有不变的元素,这时候我们可以使用memcpy函数来定义一个用来输出的数组,将digits前面的元素都复制过去,返回的长度也要复制过去,return returnbuff.
memcpy(returnbuff,digits,sizeof(int)*digitsSize);
* returnSize=digitsSize;
return returnbuff;
情况二
最后一位是九,将会影响前面的元素。
else
{
int* returnbuff=(int*)calloc((digitsSize+1),sizeof(int));
*returnSize=digitsSize+1;
memcpy(&returnbuff[1],digits,sizeof(int)*digitsSize);
addone(returnbuff,digitsSize+1);
if(returnbuff[0]==0)
{
*returnSize=digitsSize;
memcpy(digits,&returnbuff[1],sizeof(int)*digitsSize);
return digits;
}
return returnbuff;
}
继续使用calloc来分配内存,确保所有位都初始化为0。由于可能会遇到全部位都是九的情况,所有我们需要在数组的开头预留一个位置。由于数组元素每个都后移一位,输出的长度也要加一。
int* returnbuff=(int*)calloc((digitsSize+1),sizeof(int));
*returnSize=digitsSize+1;
从索引为一的位置将digits数组的元素都复制给returnbuff。
memcpy(&returnbuff[1],digits,sizeof(int)*digitsSize);
接下来就要使用递归函数来处理returnbuff中每一个元素是否需要变化了。既然是改变数组里的元素,所以我们构造的递归函数接受的第一个参数就是一个指向整数的指针returnbuff,在构造函数时用int* addrbuff表示,buffpos 是一个整数变量,它用于表示数组中当前正在处理的元素的位置。这个变量的主要功能是作为一个索引,帮助函数 addone 和 plusOne 在数组中定位当前需要处理的元素。
void addone(int* addrbuff,int buffpos)
{
}
buffpos 递减,表示从数组的最后一个元素向前处理。
buffpos--;
然后分类讨论
情况一
如果 buffpos 小于 0,表示已经处理完所有元素,函数返回。
if(buffpos<0)
{
return;
}
情况二
如果当前元素的值加一后大于或等于 10,则该元素设置为 0(表示产生进位),并递归调用 addone 函数继续处理前一个元素。
if(addrbuff[buffpos]+1>=10)
{
addrbuff[buffpos]=0;
addone(addrbuff,buffpos);
}
情况三
如果当前元素的值加一后小于 10,则直接将该元素的值加一,并结束递归
else
{
addrbuff[buffpos]=addrbuff[buffpos]+1;
}
通过这三类情况的分类讨论,我们通过递归的方法实现了整型数组中模拟进位操作,完成进位后,如果数组索引为0的位置的元素为0,那么说明我们预留给每个位都是9这种可能性没有发生,最大的一位没有进位,最大的一位代表的0没有意义,那么我们要抛弃掉数组最前面的一个元素。
if(returnbuff[0]==0)
{
*returnSize=digitsSize;
memcpy(digits,&returnbuff[1],sizeof(int)*digitsSize);
return digits;
}
如果不是这种情况,说明最大位成功进一,我们输出要输出完整的数组
return returnbuff;
接下来附完整代码
/*
* Note: The returned array must be malloced, assume caller calls free().
*/
void addone(int* addrbuff,int buffpos)
{
buffpos--;
if(buffpos<0)
{
return;
}
if(addrbuff[buffpos]+1>=10)
{
addrbuff[buffpos]=0;
addone(addrbuff,buffpos);
}
else
{
addrbuff[buffpos]=addrbuff[buffpos]+1;
}
}
int* plusOne(int* digits,int digitsSize,int* returnSize)
{
if(digits[digitsSize-1]!=9)
{
int* returnbuff=(int*)calloc(digitsSize,sizeof(int));
digits[digitsSize-1]=digits[digitsSize-1]+1;
memcpy(returnbuff,digits,sizeof(int)*digitsSize);
* returnSize=digitsSize;
return returnbuff;
}
else
{
int* returnbuff=(int*)calloc((digitsSize+1),sizeof(int));
*returnSize=digitsSize+1;
memcpy(&returnbuff[1],digits,sizeof(int)*digitsSize);
addone(returnbuff,digitsSize+1);
if(returnbuff[0]==0)
{
*returnSize=digitsSize;
memcpy(digits,&returnbuff[1],sizeof(int)*digitsSize);
return digits;
}
return returnbuff;
}
}
知识点精炼
递归:递归是一种编程技巧,它允许函数调用自身来解决问题。当我们要解决一个复杂的问题不断处理一个数据直到这个数据达到我们的要求时,我们可以考虑使用递归的方法。
memcpy函数:meccpy函数的原型是void *memcpy(void *dest, const void *src, size_t n);
dest:指向目的内存块的指针,即要复制到的位置。
src:指向源内存块的指针,即要复制的数据的起始位置。
n:要复制的字节数。
memcpy 返回一个指向 dest 的指针。
memcpy 函数从源地址 src 处复制 n 个字节到目标地址 dest。复制过程会逐字节进行,不会受到数据类型的限制。这意味着 memcpy 可以用来复制整型数组、字符数组、结构体等任何类型的数据