面试题02.04.分割链表,从这道题中收获到很多。
最开始我尝试的时候写的代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int carry = 0;
ListNode *res = l1,*pre = l1;
while(l1&&l2)
{
l1->val += l2->val + carry;
carry = 0;
if(l1->val >= 10)
{
l1->val %= 10;
carry = 1;
}
pre = l1;
l1 = l1->next;
l2 = l2->next;
}
if(carry)
{
ListNode *last = new ListNode(1);
last->next = NULL;
pre->next = last;
}
return res;
}
};
这里主要存在的问题是想当然的认为链表l1长度大于l2,而且为了处理最后进位的情形,在最后添加了特殊处理,但这个特殊处理有可能会引发更多的进位,这里没有处理。
参考评论区大神的代码,优化后的代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *head = new ListNode(-1), *p1 = l1, *p2 = l2, *p = head;
int carry = 0;
while(p1 || p2 || carry)
{
int sum = 0;
if(p1)
{
sum += p1->val;
p1 = p1->next;
}
if(p2)
{
sum += p2->val;
p2 = p2->next;
}
sum += carry;
ListNode *node = new ListNode(sum %10);
(sum >= 10)? carry = 1:carry = 0;
p->next = node;
p = p->next;
}
return head->next;
}
};
上面的代码非常值得学习,首先使用了带头结点的链表,这样可以简化一些判断逻辑。
其次是上面的while判断条件与我最开始写的代码不同,使用||可以将l1与l2长度不相同时放在while中处理,而不是处理完后在流程外面拼接。这里是任一链表不空或存在进位,那么流程继续。
最后一点是每次一个结点都申请内存,而不是使用链表l1或l2,除了更加贴近工程实践之外,更主要的一点是例如当l1+l2最后多出一位,如果是这种场景是无法复用l1和l2元素。
简单来说上面代码的优点主要是:
1.带头结点,优化判断逻辑
2.while判断条件
兼容长度不相等情况
兼容存在进位后,长度超过原链表情况