题目描述
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入: l1 = [2,4,3], l2 = [5,6,4]
输出: [7,0,8]
解释: 342 + 465 = 807.
示例 2:
输入: l1 = [0], l2 = [0]
输出: [0]
示例 3:
输入: 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
- 题目数据保证列表表示的数字不含前导零
代码及注释
/*** Definition for singly-linked list.* type ListNode struct {* Val int* Next *ListNode* }*/func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {// 创建一个虚拟头节点作为结果链表的起始节点dummy := &ListNode{}// 创建一个指针 cur 指向当前结果链表的末尾cur := dummy// 创建一个变量 reminder 用于记录进位reminder := 0// 遍历两个链表,将对应节点的值相加,考虑进位,构建结果链表for l1 != nil && l2 != nil {// 计算当前节点的值,并考虑进位sum := l1.Val + l2.Val + reminder// 更新进位reminder = sum / 10// 将当前节点的值加入到结果链表中cur.Next = &ListNode{Val: sum % 10}// 移动指针到下一个节点l1 = l1.Nextl2 = l2.Nextcur = cur.Next}// 处理其中一个链表还有剩余节点的情况for l1 != nil {// 计算当前节点的值,并考虑进位sum := l1.Val + reminder// 更新进位reminder = sum / 10// 将当前节点的值加入到结果链表中cur.Next = &ListNode{Val: sum % 10}// 移动指针到下一个节点l1 = l1.Nextcur = cur.Next}for l2 != nil {// 计算当前节点的值,并考虑进位sum := l2.Val + reminder// 更新进位reminder = sum / 10// 将当前节点的值加入到结果链表中cur.Next = &ListNode{Val: sum % 10}// 移动指针到下一个节点l2 = l2.Nextcur = cur.Next}// 处理最高位有进位的情况if reminder > 0 {cur.Next = &ListNode{Val: reminder}}// 返回结果链表,从虚拟头节点的下一个节点开始return dummy.Next
}
代码解释
初始化
-
dummy 虚拟头节点:创建一个虚拟的头节点
dummy
,用于指向结果链表的开始,这样在处理时可以简化逻辑,不需要特殊处理头节点。 -
cur 指针:创建一个指针
cur
,指向当前结果链表的末尾,用于构建结果链表。 -
reminder 进位:创建一个
reminder
变量,用于记录每一步的进位值。dummy := &ListNode{} cur := dummy reminder := 0
遍历链表并相加
-
使用一个循环遍历两个链表
l1
和l2
,同时将对应位置的节点值相加,并考虑上一步的进位值。for l1 != nil && l2 != nil {sum := l1.Val + l2.Val + reminderreminder = sum / 10cur.Next = &ListNode{Val: sum % 10}l1 = l1.Nextl2 = l2.Nextcur = cur.Next }
处理剩余的链表节点
-
如果其中一个链表
l1
还有剩余的节点,将其与reminder
相加并添加到结果链表中。for l1 != nil {sum := l1.Val + reminderreminder = sum / 10cur.Next = &ListNode{Val: sum % 10}l1 = l1.Nextcur = cur.Next }for l2 != nil {sum := l2.Val + reminderreminder = sum / 10cur.Next = &ListNode{Val: sum % 10}l2 = l2.Nextcur = cur.Next }
处理最高位的进位
-
如果在处理完两个链表的所有节点后,
reminder
仍然大于 0,需要在结果链表的最后添加一个新的节点来表示这个进位。if reminder > 0 {cur.Next = &ListNode{Val: reminder} }
返回结果链表
-
返回结果链表,从虚拟头节点
dummy
的下一个节点开始。return dummy.Next
通过这种方式,我们可以高效地计算出两个链表的和,并得到正确的结果。这个算法的时间复杂度是 O(max(n, m)),其中 n 和 m 分别是两个链表的长度。