昨天小试牛刀,做了一下第二题,感觉还不错,但是做完之后再看到别人的代码之后,就只剩下震惊于心塞了
文章目录如下
(1)自己的思路
(2)自己的代码
(3)别人的思路
(4)别人的代码
(5)对比自己的不足之处
题目如下
You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Subscribe to see which companies asked this question
(1)自己的思路
a.拿到这道题,首先我想到的是进位的问题,例如上面所给的例子(2 -> 4 -> 3) + (5 -> 6 -> 4)中间的4+6=10,这样的话就得往前进一位,同时该位的数字还要减去10。如何让程序知道什么时候进位呢?可以通过各bool变量flag来表示,当某一位大于10时,那么设置flag为true,否则为false。
b.第二个想到的是,如果是两个数的位数不一样该怎么办呢?例如(2 -> 4 ) + (5 -> 6 -> 4),这样的话得判断那个加数的位数要小一些,然后相加完之后,只需要把位数多的加数的剩余位直接赋值给目标就可以了,由于加数都存放在链表中,所以可以通过判断链表的长度(即尾指针是否为null来解决),下面代码片段展示了当l1的位数比l2小时候的情况,其中l3为目标链表(保存结果的链表),其中下面的代码也考虑到了位数增加的这种情况,例如(2) + (8 ->9)=(0->0->1),结果比两个加数的位数还要多一位。我的解决思路是,将多出的那一位添加到位数长的那个加数上去,然后在下一轮循环的时候,赋值给目标链表
//l1为空 if (l1 == NULL) //判断前一位是否大于10 if (flag) { l3->val = l2->val + 1; if (l3->val >= 10) { l3->val = l3->val - 10; //如果满10进一之后,l2没有更高的位了,那么要重新申请一个位 if (l2 == NULL) l2 = new ListNode(1); //要在continue之前就执行l2 = l2->next;因为如果在60行再执行该操作的话,那么永远都不会执行这句话,以为continue会直接返回循环 l2 = l2->next; flag = true; continue; } else { flag = false; l2 = l2->next; continue; } } //前一位小于10,那么直接将L2上的值复制给l3即可 else { l3->val = l2->val; flag = false; l2 = l2->next; continue; }
c.第三点是关于合适终止的问题,我觉得终止应该由两个加数的长度来决定,更精确的来讲因该是有长度长的那个加数的长度来决定,由于原始加数l1与l2的长度已经固定,无法考虑到b中所说的位数增加的那种情况(2) + (8 ->9)=(0->0->1),所以在判断条件中,还应该添加flag变量,因为当flag==true的时候,意味着有进位要处理
所以代码结构如下
class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { //判断是否大于10 bool flag = false; ListNode *l3 = new ListNode(0); ListNode *head = l3; while (l1!=NULL | l2!=NULL | flag) { if (l3->next == NULL) { l3->next = new ListNode(0); l3 = l3->next; } //首先判断l1、l2之一是否为空 ...//接下来处理l1,l2都不为空的情况 ...
} return head->next; } };
d.正常的情况(l1,l2都不为空的情况)就是那种最普通的相加,即l1,l2位数一致,在相加的过程中没有进位运算,这样的话只需要将对应位的值相加并将结果赋值给l3对应的元素即可。
所以完整代码如下:
(2)自己的代码
class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { //判断是否大于10 bool flag = false; ListNode *l3 = new ListNode(0); ListNode *head = l3; while (l1!=NULL | l2!=NULL | flag) { if (l3->next == NULL) { l3->next = new ListNode(0); l3 = l3->next; } //首先判断l1、l2之一是否为空 if (l1 == NULL | l2 == NULL) { if(l1==NULL&&l2==NULL) { l3->val = 1; flag = false; break; } //l1为空 if (l1 == NULL) //判断前一位是否大于10 if (flag) { l3->val = l2->val + 1; if (l3->val >= 10) { l3->val = l3->val - 10; //如果满10进一之后,l2没有更高的位了,那么要重新申请一个位 if (l2 == NULL) l2 = new ListNode(1); //要在continue之前就执行l2 = l2->next;因为如果在60行再执行该操作的话,那么永远都不会执行这句话,以为continue会直接返回循环 l2 = l2->next; flag = true; continue; } else { flag = false; l2 = l2->next; continue; } } //前一位小于10,那么直接将L2上的值复制给l3即可 else { l3->val = l2->val; flag = false; l2 = l2->next; continue; } //l2为空,与l1为空处理类似 else //判断前一位是否大于10 if (flag) { l3->val = l1->val + 1; if (l3->val >= 10) { l3->val = l3->val - 10; //如果满10进一之后,l2没有更高的位了,那么要重新申请一个位 if (l1 == NULL) l1 = new ListNode(1); flag = true; l1 = l1->next; continue; } else { flag = false; l1 = l1->next; continue; } } //前一位小于10,那么直接将L2上的值复制给l3即可 else { l3->val = l1->val; l1 = l1->next; flag = false; continue; }; } //接下来处理l1,l2都不为空的情况 int tmp1 = l1->val; int tmp2 = l2->val; int tmp3 = 0; if (flag) { tmp3 = tmp1 + tmp2 + 1; } else { tmp3 = tmp1 + tmp2; } //判断tmp3是否大于10 if (tmp3 >= 10) { tmp3 = tmp3 - 10; flag = true; } else flag = false; l3->val = tmp3; l2 = l2->next; l1 = l1->next; } return head->next; } };
写了100多行,调试成功之后,还没来得及高兴,就被更好地代码打懵逼了……
给出更好地代码思路
(3)别人的思路
a.因为这是两个数的相加,所以即使是进位,最多也只能往高位进1,那么可以用单独的一个变量carry来保存这个进位,不管有没有进位,在运算的过程中一直保持着l3->val = l1->val + l2->val + carry;如果有进位,那么让carry=1,如果没有,让carry=0.这样的好处是不管有没有进位,都可以进行统一的操作,而不用像我那样分类来讨论。这样的话便可以极大地减少了代码量
(4)别人的代码
class Solution { public: ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { ListNode dummy(-1); // 头节点 int carry = 0; ListNode *prev = &dummy; for (ListNode *pa = l1, *pb = l2; pa != nullptr || pb != nullptr; pa = pa == nullptr ? nullptr : pa->next, pb = pb == nullptr ? nullptr : pb->next, prev = prev->next) { const int ai = pa == nullptr ? 0 : pa->val; const int bi = pb == nullptr ? 0 : pb->val; const int value = (ai + bi + carry) % 10; carry = (ai + bi + carry) / 10; prev->next = new ListNode(value); // 尾插法 } if (carry > 0) prev->next = new ListNode(carry); return dummy.next; } };
(5)对比自己的不足之处
见(3)的分析~