两数相加:链表上的竖式进位
头节点是个位,两条链已经对齐。每位只做 a+b+进位,写下 sum%10,把 sum/10 传给下一位。
同时走两条链表,sum = 进位 + 当前位(缺位当 0)。新节点写 sum%10,进位改成 sum/10。循环条件是「至少还有一条链,或者进位还在」。最后进位非零要补最高位。时间 O(max(m,n)),空间 O(max(m,n))。
这是 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 把头放在最高位,就必须先反转或用栈,进位方向和本题相反。
竖式:缺位当 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。
进位必须交给下一位,不能就地清掉
主例十位: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。漏进位是这道题第一常见的错。
短链补 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。
九行 Go:竖式加法
func addTwoNumbers(l1, l2 *ListNode) *ListNode {dummy := &ListNode{}cur := dummycarry := 0for l1 != nil || l2 != nil || carry > 0 {sum := carryif 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 / 10cur = 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。