给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
原题地址:两数相加
或直转到:https://leetcode-cn.com/problems/add-two-numbers/
- 我的题解
void _myfunc(struct ListNode* l1,struct ListNode* l2) {
int shuzi;
shuzi = 0;
if (l1 != NULL && l2 != NULL) {
shuzi = l1->val + l2->val;
if (shuzi > 9 && l1->next != NULL) {
l1->val = shuzi - 10;
l2->val = l1 -> val;
(l1->next)->val += 1;//猜想(9+9=18,18+1<20所以没毛病,最大进位1)
}
if (shuzi < 10) {
l1->val = shuzi;
l2->val=l1->val;
}
}//没毛病,除了可能下一位进位到10不+
}
void dushanqishen(struct ListNode* thisnode){
if(thisnode->val>9&&thisnode->next!=NULL){
(thisnode->next)->val++;
thisnode->val=thisnode->val-10;
dushanqishen(thisnode->next);
}
if(thisnode->val>9&&thisnode->next==NULL){
struct ListNode* lastnode =(struct ListNode*)malloc(sizeof(struct ListNode));
lastnode->val=1;
lastnode->next=NULL;
thisnode->val=thisnode->val-10;
(thisnode->next)=lastnode;
}
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
int i = 0;//确认因子
struct ListNode* chang;
struct ListNode* duan;
chang=l1;
duan=l2;
while (duan->next!=NULL&&chang->next!=NULL){
_myfunc(chang ,duan);//在while里自己动
chang=chang->next;
duan=duan->next;
}
if(chang->next==NULL&&duan->next==NULL){
chang->val+=duan->val;
dushanqishen(chang);
return l1;
}
if(chang->next!=NULL){
chang->val+=duan->val;
dushanqishen(chang);
return l1;
}
if(duan->next!=NULL){
duan->val+=chang->val;
dushanqishen(duan);
return l2;
}
return l1;
}
/*分析题意
- 两个链表中的数字各代表同一数字的不同位数
- 求相加之后的数字
- 我决定从最小的加起,这样进位是最简单的,根据题意可知
- 数字都是倒过来装的
- 因此前面的反而是最小的一位,即个位
- */
下面书写正常编写程序的思路,在这道题里我遇到了很多艰难险阻,不过大多是因为我脑袋不好使:
1、明确链表数据结构,且数量为2,两个链表各有长短
2、我选择直接进行操作,之前试着找出最长数组,然后对长短数组进行有序操作,发现我的编译。。。。超时了,因此我决定先解决共同长度那部分,长短不一的一段之后再处理
3、长短相同部分,即两个指针有序移动都非空的部分,算法为val相加小于9直接赋值给其中两数组(这里主数组的选择是根据系统先后给的空间的,先给的就是主数组),大于9的将减10的数字留给主数组指定位置,下一位进一(即(l->next)->val)。
4、尽管这样,我也只能判断到两段数据都有next的时候,因为新的进位可能会造成新空间的创建,这里留给下满的函数。结束这段操作后就要进行新的操作了。
5、到上边结束后,我们其实还有一个数据没有操作,也就是对应最短数组的最后一位角标的,两个数组的数据,首先主数组的是已经处理完进位的了,我们需要手动给这一位加好,然后进入我们编写的"独善其身"函数,因为到这里我们只需要处理一段数据了。
6、判断next指向不为null就可以进入了,因为上面的循环,我们知道next肯定有一个为null。不要忘了考虑两个都是null的情况(这个会在debug过程中出现)。
7、下面就是常规操作,由于短数组最后一个数字还没处理,记得将短数组最后一个数加入长数组中。随后将长数组对应段数组最后元素角标的元素地址装入“独善其身”。妥妥的。
8、独善其身拥有强大的功能,可以自己进行进位,主要是处理段数组最后一位,也可以在长数组最后一位产生新的进位时,创建新的结点空间。
大体思路就是这样了。
我好想看看大神简短的代码啊!
- Dalao的代码
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
int sum,flag;
struct ListNode* pln1;
pln1=l1;
sum=l1->val+l2->val+flag;
flag=((l1->val=sum%10)!=sum);
while(l1->next!=NULL && l2->next!=NULL){
l1=l1->next;
l2=l2->next;
sum=l1->val+l2->val+flag; //判断上次的flag是否为1
flag=((l1->val=sum%10)!=sum);//在这里转换,且给下次的sum计算用,进位
}
if(l1->next==NULL)
l1->next=l2->next;//短衔接长,要么不用衔接
while(l1->next!=NULL && flag){
l1=l1->next;
sum=l1->val+flag;
flag=((l1->val=sum%10)!=sum);//在这里转换,且给下次的sum计算用,进位
}
if(l1->next==NULL && flag){
l1->next=l2;
l1=l1->next;
l1->val=flag;
l1->next=NULL;
}
return pln1;
}
//作者:musing-nevvtonlci
通过研读代码发现,大佬的大体思路和我是一样的,不过也有一些区别
1、首先,由于大佬利用flag标志,用来接收是否需要进位,且每次循环中的flag是给下次循环中的sum用的,这样大大减少了代码量,不需要单独写函数了。
2、其次,没有分类进行衔接,我进行衔接的时候进行了判断,利用了next是否为NULL,这里他就判断了一次,省去了一次判断,若其中一个next为null,则直接用短的衔接长的next。
3、最后,利用while进行了我的“独善其身操作”。其中进位方法也是利用的flag,而不是像我利用更多的代码实现相同的操作。若最后一位还需要进位,这个code作者是利用了老的另一条短数组中的空间。因此不需要malloc。省去了一定空间。
总之,大佬利用一个flag,将整个程序衔接起来了。而不是像我,将程序割裂开来,每部分实现不同的功能。虽然说我这么写有我这么写的好处,不过大老这种思想真的是值得借鉴,思路如此清晰,即使是高耦合我也认了。说到底就是,人家是强者的烦恼,我是弱鸡的烦恼。