当前:LC2 · 两数相加 · 首次出现于 Day 11 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC2 · Add Two Numbers · 链表

两数相加:链表上的竖式进位

头节点是个位,两条链已经对齐。每位只做 a+b+进位,写下 sum%10,把 sum/10 传给下一位。

同时走两条链表,sum = 进位 + 当前位(缺位当 0)。新节点写 sum%10,进位改成 sum/10。循环条件是「至少还有一条链,或者进位还在」。最后进位非零要补最高位。时间 O(max(m,n)),空间 O(max(m,n))。

时间 O(max(m,n))空间 O(max(m,n))结论先行 · 全文约 6 节
导读

这是 LeetCode 2. Add Two Numbers。大白话:两条非空链表各表示一个非负整数,数字按逆序存放,头节点是个位,每个节点只存一位 0 到 9。把两个数相加,按同样的逆序链表返回。除了 0 本身,表示里不会有前导零。

主例 l1 = 2→4→3,表示 342;l2 = 5→6→4,表示 465。342+465=807,答案是 7→0→8。不要把头节点当成最高位:2→4→3 不是 243。

先整表转成整数再加,会在很长的链上溢出。缺的不是大数库,而是小学竖式:个位已经在头上对齐,只要逐位加、把进位传下去。

头节点是个位,不是最高位

2→4→3 从左往右读是个位 2、十位 4、百位 3,数值 342。演示第一帧停在个位 2,第二帧停在百位 3。若把链表当普通数组正向读成 243,后面每一位都会加错。

题目把低位放在头上,不是刁难。加法必须从个位开始,单链表又只能从头往 Next 走,这个存放顺序让「当前走到的节点」正好是当前该加的那一位,不必先反转。

低位在前头是个位,两条链天然对齐。LC445 把头放在最高位,就必须先反转或用栈,进位方向和本题相反。
2→4→3 表示 342:头是个位
2→4→3 表示什么数?
2
4
3
nums[0] = 2个位 → 2×1 + 4×10 + 3×100 = 342

竖式:缺位当 0,写下个位

小学竖式:个位对个位,满十向前进一。这里两条链的头已经是个位,对齐是现成的。某一条先走完,这一位就当 0,不要提前结束——另一条剩下的位还要加,进位也可能还在。

每一位:sum = carry + (l1 当前位或 0) + (l2 当前位或 0);结果链写下 sum % 10;carry 改成 sum / 10;两条指针能走就走 Next。dummy 头挂结果,避免单独处理第一个节点。

主例个位 2+5+0=7,写下 7,进位 0。演示竖式第一帧。十位见下一节。百位 3+4+1=8,写下 8,进位 0。演示第三帧结果已是 7→0→8。

竖式对齐:个位对个位,逐位相加
l1(低位在前)
2
4
3
l2(低位在前)
5
6
4

进位必须交给下一位,不能就地清掉

主例十位:4+6+0=10。写下 10%10=0,进位变成 1。演示进位第一帧,index=1,sum=10,carry=1。若这里把进位丢掉,百位会做成 3+4=7,整条结果变成 7→0→7,807 错成 707。

下一拍百位必须加上这个 1:3+4+1=8,写下 8,进位 0。演示第二帧结果 7→0→8。进位不是「加完就忘」,它是下一位 sum 的起点。代码里每一轮 sum 先等于旧进位,再加两个当前位,最后才更新进位,顺序不能乱。

进位两位数字加进位最大是 9+9+1=19,进位只可能是 0 或 1。漏进位是这道题第一常见的错。
4+6=10:写 0 进 1,下一轮 3+4+1=8
l1(低位在前)
2
4
3
l2(低位在前)
5
6
4
和 = 10 → 写 0,进位 1进位 1 传入下一位 →

短链补 0,最后的进位要另开节点

长度不同时,短的那条走完就当 0,长的继续加进位。循环条件不能写成「两条都非空」:那样会丢掉长链尾巴,也会丢掉最高位进位。正确条件是 l1 还在,或 l2 还在,或 carry > 0。

对照链 9→9→9→9→9→9→9 加 9→9→9→9,也就是 9999999+9999=10009998。低四位每位都是 9+9+进位,写下 8、9、9、9;后三位是 9+0+1,写下 0、0、0,进位仍是 1;两条链都空了,还要再开一个节点写 1。演示两帧停在后半段的进位 1,以及最终 8→9→9→9→0→0→0→1。主例没有这一步,因为最后进位已经是 0。

长链走完补 0;最后进位非零要补最高位
l1(低位在前)
9
9
9
9
9
9
9
l2(低位在前)
9
9
9
9
进位 1 传入下一位 →

九行 Go:竖式加法

solution.goGo
func addTwoNumbers(l1, l2 *ListNode) *ListNode {
dummy := &ListNode{}
cur := dummy
carry := 0
for l1 != nil || l2 != nil || carry > 0 {
sum := carry
if l1 != nil { sum += l1.Val; l1 = l1.Next }
if l2 != nil { sum += l2.Val; l2 = l2.Next }
cur.Next = &ListNode{Val: sum % 10}
carry = sum / 10
cur = cur.Next
}
return dummy.Next
}

1dummy 后面才是真头。返回 dummy.Next,主例是 7 那个节点。

2循环条件含 carry。主例最后进位是 0,不会多写;9999999+9999 会靠它补出最高位 1。

3sum 从旧进位起。主例十位是 0+4+6=10,写下 0,进位 1 交给百位;百位必须加上这个 1 才是 8。

4链走完就跳过,这一位当 0。写下 sum%10,进位换成 sum/10。

总结

头是个位,逐位 a+b+进位。主例十位 4+6 写 0 进 1,答案 7→0→8。

  • 2→4→3 是 342 不是 243。逆序存放让竖式从头部对齐。
  • 进位是下一位的起点。主例丢掉十位的 1,807 会错成 707。
  • 循环要包含 carry,否则最高位的 1 写不出来。短链缺位当 0。
同族题目
LC445两数相加 II(高位在前)LC67二进制求和(同款进位)LC415字符串相加(同款竖式)