题目描述
本文是leetcode第2题的题解,题目描述摘自leetcode。如下
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
如图, 342 和 465 相加,得到的结果为 807,但 342 和 465 以及结果均由链表表示,链表元素从左至右依次是数字的个位、十位、百位。
举例:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
输入:l1 = [0], l2 = [0]
输出:[0]
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
限制:
每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零
解题思路
此题的解法比较简单,按照加法操作做模拟就可以。
加法操作:先从个位开始相加,逢10进1,直到两个加数的最高位都已完成加操作。
正确的数字个位是在最右,而此题为了减小相加难度,将个位放在了链表的第一个元素,从左至右依次是个十百千等,试想一下,如果此题遵循我们的习惯,将个位放在链表最后一个位置,难度是不是就加大了?感兴趣可以去尝试code一下个位在最右的解法。
ok,回到正题,那么此题,其实只需要同时遍历两个链表,将对应位的元素相加 + 上一位的进位值,直到两个链表都处理完最后一个元素,最后再关注一下最后一位相加有没有产生进位,整个加法操作就完成了。
几个注意的点:
- 每一位相加都要加上一位的进位值,个位相加时我们将进位值初始为0
- 两个链表元素个数可能相等,也可能不等,因此我们需要考虑链表长短不一的情况,其中一个已经遍历完,另一个还有剩余位的情况
- 最后一位加完,有没有产生进位,没有进位,就是进位0,有进位,就是该进位值,对于有进位的情况,链表遍历结束后,要给存储结果的链表,尾部再插入最后一位相加产生的进位。
代码
以下是我的题解,重要的代码都有注释,大家可以去leetcode,提交代码,如果有可以优化代码的地方,请在评论区留言,万分感谢
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int cb = 0; // 初始化进位值为0
ListNode* dummyNode = new ListNode(-1); // 定义一个哑节点,链表第一个节点的上一个节点,用于辅助
ListNode* tail = dummyNode;
int val;
int a, b;
for( ; l1 || l2; )
{
if(!l1) a = 0; else a = l1->val, l1 = l1->next; // 下面会进行解释
if(!l2) b = 0; else b = l2->val, l2 = l2->next;
val = a + b + cb; // 对应位值相加 + 上一位进位
cb = val / 10; // 产生当前位的进位值
tail = tail->next = new ListNode(val % 10); // 将当前位的相加结果 % 10 插入结果链表尾部
}
if(cb) // 处理最后一位产生的进位值
{
tail = tail->next = new ListNode(cb);
}
ListNode* head = dummyNode->next; // 哑节点不需要,返回链表第一个节点
delete dummyNode;
return head;
}
};
上述代码中如下部分,是笔者浏览海外版leetcode社区题解中,看到的写的很巧妙的地方,所以特地学习了下。
如果不这么写,其实我们也可以将循环相加的循环条件定义为 while (l1 && l2)
,然后在循环退出后,处理长出来的那部分链表。
但好的东西需要学习,所以看下这段代码吧
if(!l1) a = 0; else a = l1->val, l1 = l1->next; // 这里逻辑上做了优化,下面会进行解释
if(!l2) b = 0; else b = l2->val, l2 = l2->next;
这段代码巧妙的处理了两个链表长短不一的情况,无论哪个链表先结束,只需要将该链表对应的数的高位都设置为0,去和另一位相加,如下图所示:
上面的l1链表,只有三个元素243,因此在进行千位相加时,l1元素就已经是NULL节点了,但我们假设还有节点,只不过该“节点”的元素是0.