原题链接: 2. 两数相加 - 力扣(Leetcode)
tag: 链表.
一. 题目
给你两个 非空 的链表, 表示两个非负的整数. 它们每位数字都是按照 逆序 的方式存储的, 并且每个节点只能存储 一位 数字.
请你将两个数相加, 并以相同形式返回一个表示和的链表.
你可以假设除了数字 0 之外, 这两个数都不会以 0 开头.
二. 题解
本题我们通过将两个链表的节点相加后再 尾插 到表示加的链表中来对两个链表进行相加.
由于尾插第一个节点时表示加的链表中没有节点, 即 tail == nullptr, 无法通过 tail->next = new ListNode(carry % 10); 来尾插相加后的节点, 需要分类讨论.
为了避免这种额外的讨论, 我们引入虚拟头节点(dummy)的概念.
设置虚拟头节点, 即在链表的头节点前新插入一个节点. 如此, 链表的头节点便有了前驱节点(即dummy), 尾插时就不需要进行额外的讨论.
ListNode* dummy = new ListNode(), * tail = dummy;
int carry = 0;
当 l1 不为空 或者 l2 不为空 或者 进位 carry 不为 0 时, 循环迭代.
l1 != nullptr;
carry += l1->val;
l1 = l1->next; 更新 l1 指针.
l2 != nullptr;
carry += l2->val;
l2 = l2->next; 更新 l2 指针.
tail->next = new ListNode(carry % 10); 将新节点尾插到 dummy 后面.
tail = tail->next; 更新 tail 指针.
carry /= 10; carry 进位.
重复这一步骤, 直到 while 循环终止.
ListNode* head = dummy->next;
delete dummy;
return head; 返回新链表的头节点.
三. 复杂度分析
时间复杂度: O(max(M, N)), 其中 M 和 N 分别表示两个链表的长度.
空间复杂度: O(1).
四. 代码
/**
* 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) {
ListNode* dummy = new ListNode(), * tail = dummy; // 创造一个虚拟头节点 dummy 用来尾插新节点
int carry = 0; // carry 表示当前位的值
while (l1 || l2 || carry) { // 从低位到高位遍历两个非负整数
if (l1) {
carry += l1->val;
l1 = l1->next; // 更新 l1 指针
}
if (l2) {
carry += l2->val;
l2 = l2->next; // 更新 l2 指针
}
tail->next = new ListNode(carry % 10); // 将新节点尾插到 dummy 后面
tail = tail->next; // 更新 tail 指针
carry /= 10; // carry 进位
}
ListNode* head = dummy->next; // 返回新链表的头节点
delete dummy;
return head;
}
};