题目描述
思路解析
一句话答案:LeetCode 2 两数相加的标准解法是模拟竖式加法:两条链表低位在前,同步遍历逐位取数,加上进位变量 carry,当前位写 (a + b + carry) % 10,新进位取十位,循环条件是 l1、l2、carry 三者任一还有剩。时间 O(max(m,n))、空间 O(max(m,n)) 用于结果链表。
这道题真正在问什么
两个非负整数各用一条链表表示,数位按「低位在前」存放(个位是头节点),要求返回它们的和,同样用低位在前的链表表示。数字可能非常长,长到任何整数类型都装不下——所以别想着把链表还原成数字再相加,必须像小学竖式那样逐位处理。
为什么低位在前反而是送分设计
竖式加法天然从个位算起,因为低位产生的进位要传给高位。链表低位在前,意味着从两条链的头节点开始同步往后走,遍历顺序恰好就是加法需要的计算顺序,一遍顺序遍历直接出结果,连反转都不用。如果题目改成高位在前(LeetCode 445),反而要先用栈或反转把顺序倒过来才能加。
想通这一点,整道题就从「链表技巧题」还原成它的本质:用链表外壳包着的高精度加法模拟。
进位 carry 为什么是整个算法的核心
逐位相加时,各位之间唯一的耦合就是进位:本位的和超过 9,要往高一位送一个 1。把这件事收敛成一个变量 carry,每一位的计算就完全统一:总和 = a + b + carry,当前位写总和 % 10,新的 carry 是总和 // 10。由于每位相加最大是 9 + 9 + 1 = 19,carry 只会是 0 或 1,永远不会连环爆位。
正确性不需要额外论证——这就是竖式加法本身的规则,算法只是把人手算的过程逐字翻译成代码。真正的功夫全在边界处理上。
循环条件为什么要带上 carry
两条链长度可能不同,短的先走完后,缺的位当 0 参与运算即可,不需要补节点。但最容易漏的一种情况是:两条链都走完了,carry 还是 1——比如 5 + 5,两条链各一个节点,加完后必须再补一个最高位节点存这个 1,否则 10 会被算成 0。
把循环条件写成「l1 或 l2 或 carry 任一非空非零就继续」,最后这次补位就被自然纳入循环,不用在循环外单独写一段收尾代码。这是本题第一坑,也是面试官检查你是否真正模拟过竖式的试金石。
哑结点、复杂度与常见变体
结果链表的头节点在循环第一轮才产生,所以照例用哑结点 dummy 起头,接第一个节点和接后续节点写法一致,最后返回 dummy.next。
时间 O(max(m,n)):两条链各扫一遍,循环轮数由较长的链加上可能的一次补位决定。空间 O(max(m,n)):结果链表最长比长链多一个节点;除结果外只用了 carry 一个额外变量。变体方面,高位在前的版本先把两条链压栈再从栈顶逐位相加、用头插法建结果,核心的 carry 逻辑与本题完全相同。
▶ 动画逐步走查(文字版)——想跟着上方动画一帧帧对照就展开
记住这条,下面每一位都在套它。
上两行是 A、B(低位在前),最下一行是结果链表,先留空。我们用一个进位变量 carry 从 0 开始。
两个指针 p、q 分别指向 A、B 的头(个位),cur 指向要写的结果位。carry=0,开始逐位相加。
第 0 位:a=3,b=7,进位 carry=0。cur = 3+7+0 = 10。
10 % 10 = 0 写进结果第 0 位;10 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 1 位:a=8,b=5,进位 carry=1。cur = 8+5+1 = 14。
14 % 10 = 4 写进结果第 1 位;14 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 2 位:a=5,b=8,进位 carry=1。cur = 5+8+1 = 14。
14 % 10 = 4 写进结果第 2 位;14 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 3 位:a=9,b=6,进位 carry=1。cur = 9+6+1 = 16。
16 % 10 = 6 写进结果第 3 位;16 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 4 位:a=2,b=9,进位 carry=1。cur = 2+9+1 = 12。
12 % 10 = 2 写进结果第 4 位;12 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 5 位:a=7,b=4,进位 carry=1。cur = 7+4+1 = 12。
12 % 10 = 2 写进结果第 5 位;12 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 6 位:a=6,b=8,进位 carry=1。cur = 6+8+1 = 15。
15 % 10 = 5 写进结果第 6 位;15 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 7 位:a=4,b=5,进位 carry=1。cur = 4+5+1 = 10。
10 % 10 = 0 写进结果第 7 位;10 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
第 8 位:a=8,b=3,进位 carry=1。cur = 8+3+1 = 12。
12 % 10 = 2 写进结果第 8 位;12 >= 10 ? 是 → 进位 carry 变为 1,带到下一位。
A、B 都走完了,但 carry 还是 1!别漏:要再补一个最高位节点 1。
补上最高位 1,结果链表完成:1205226440(即 1205226440)。
边界先想清,尤其是进位连锁。
两个高频追问。
参考代码
def addTwoNumbers(l1, l2): dummy = cur = ListNode(0) # 哑结点 carry = 0 while l1 or l2 or carry: a = l1.val if l1 else 0 b = l2.val if l2 else 0 carry, d = divmod(a + b + carry, 10) cur.next = ListNode(d); cur = cur.next l1 = l1.next if l1 else None l2 = l2.next if l2 else None return dummy.next复杂度
- 时间:O(max(m,n)),两表各扫一遍
- 空间:O(max(m,n)),结果链表长度
易错点
面试追问把动画讲成自己的话
追问如果数字是「高位在前」(LC445) 怎么办?
追问为什么用哑结点?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
环形链表
LeetCode 141 · 简单 · 沿着 链表 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题