2.两数相加:链表题解与分析
题目描述
给定两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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]
解题思路
核心思想
由于链表是逆序存储数字(头部是个位),我们可以直接从两个链表的头部开始相加,模拟手工计算加法的过程:
- 从个位(链表头)开始逐位相加
- 处理进位(sum = val1 + val2 + carry)
- 构建新的链表存储结果
步骤分解
- 初始化:创建一个哑节点(dummy node)作为结果链表的起点
- 遍历链表:同时遍历两个输入链表,直到两个链表都遍历完毕且没有进位
- 计算当前位和:sum = l1.val + l2.val + carry(若链表已结束,对应val为0)
- 更新进位:carry = sum // 10
- 创建新节点:将sum % 10作为新节点的值添加到结果链表
- 移动指针:将三个链表的指针都后移一位
代码实现
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def addTwoNumbers(l1: ListNode, l2: ListNode) -> ListNode:
# 创建哑节点作为结果链表的起始点
dummy = ListNode(0)
current = dummy
carry = 0 # 进位初始化为0
# 遍历两个链表,直到都为空且没有进位
while l1 or l2 or carry:
# 获取当前节点的值(若链表已结束则为0)
val1 = l1.val if l1 else 0
val2 = l2.val if l2 else 0
# 计算当前位的和与进位
total = val1 + val2 + carry
carry = total // 10 # 更新进位
current.next = ListNode(total % 10) # 创建新节点
# 移动指针
current = current.next
if l1:
l1 = l1.next
if l2:
l2 = l2.next
return dummy.next # 哑节点的下一个节点才是结果的头节点
示例分析
示例 1 详解(对应流程图)
-
输入链表:
- l1: 2 → 4 → 3(表示数字 342)
- l2: 5 → 6 → 4(表示数字 465)
-
相加过程:
- 个位:2 + 5 = 7 → 进位0 → 结果节点7
- 十位:4 + 6 = 10 → 进位1 → 结果节点0
- 百位:3 + 4 + 1(进位)= 8 → 进位0 → 结果节点8
- 结果链表:7 → 0 → 8(表示数字 807)
示例 3 特殊情况处理
当两个链表长度不同且存在连续进位时:
- l1: 9→9→9→9→9→9→9(7个9)
- l2: 9→9→9→9(4个9)
- 相加后产生连续进位,最终需要在结果链表末尾添加进位1,形成8位结果
复杂度分析
- 时间复杂度:O(max(m, n)),其中m和n分别是两个链表的长度。需要遍历到较长链表的末尾。
- 空间复杂度:O(max(m, n)),结果链表的长度最多为max(m, n) + 1(考虑最后一个进位)。
常见错误与注意事项
- 忘记处理进位:特别是最后一位相加后仍有进位的情况(如示例3)
- 链表长度不同:需要处理一个链表已结束而另一个未结束的情况
- 哑节点使用:正确使用哑节点可以简化头节点处理逻辑
- 空链表判断:虽然题目说明链表非空,但代码仍需兼容单个节点的情况
3225

被折叠的 条评论
为什么被折叠?



