题目描述
两条链表各表示一个数(每个节点一位、个位在表头),返回它们和的链表。
思路解析
两个指针同时走,每位算 a + b + carry:结果对 10 取余是这一位的数字,整除 10 是进位带到下一位。哪条短了就当它是 0。最后如果还有进位,再补一个节点。
起步 · 指针对齐个位:两个指针 p 同时停在两条链的表头(个位)。进位 carry=0,结果链表还空着(虚线占位)。逆序存的好处:表头就是个位,直接从这里开始竖式加。
个位 · 2 + 5 + 0 = 7:个位:a+b+carry = 2+5+0 = 7,没满十。本位 7 = 7%10,进位 carry = 7//10 = 0。tail.next = ListNode(7),结果链表长出第一个节点 7,tail 指向它。
十位 · 指针前移:两个输入指针各往前走一格,来到十位 4 和 6(个位已结算,标灰)。结果链表的 tail 仍停在 7。
十位 · 4 + 6 + 0 = 10 → 满十进一:十位:4+6+0 = 10,满十了!本位写 10%10 = 0,进位 carry = 10//10 = 1 带到下一位。结果链表接上 0,tail 前移。这一步的进位是最容易漏的地方。
百位 · 指针前移(别忘 carry=1):输入指针走到百位 3 和 4。注意手里还攥着上一位的进位 carry=1,这一位相加时要带上它。
百位 · 3 + 4 + 1 = 8:百位:3+4+carry(1) = 8,没满十。本位 8,进位归 0。结果链表长出第三个节点 8:7 → 0 → 8。
两条都走完 · 查最后的进位:两条输入链都走到头,指针变空。最后再看一眼 carry:这里 carry=0,不用补。如果它是 1(比如 5+5=10),还得再给结果链表接一个值为 1 的节点——这正是循环条件要带 carry 的原因。
完成:逐位相加、满十进一,返回的结果链表 7 → 0 → 8,就是 342 + 465 = 807。
链表竖式加法的三件套:逐位 divmod 取「本位/进位」、短的补 0、哨兵起头。循环条件写成 l1 or l2 or carry 是优雅收尾的关键。
参考代码(Python)
1dummy = tail = ListNode()
2carry = 0
3while l1 or l2 or carry: # 还有位或进位就继续
4 a = l1.val if l1 else 0 # 短的当 0
5 b = l2.val if l2 else 0
6 s = a + b + carry
7 carry, digit = divmod(s, 10) # 进位, 本位
8 tail.next = ListNode(digit); tail = tail.next
9 l1 = l1.next if l1 else None; l2 = l2.next if l2 else None
10return dummy.next复杂度分析
- 时间复杂度:O(max(m,n)) —— 按较长的位数走
- 空间复杂度:O(max(m,n)) —— 结果链表长度
套路模板
记住骨架:while l1 or l2 or carry、divmod 拆本位与进位、短的补 0、哨兵收尾。大数相加、字符串相加都是这套。
1dummy = tail = ListNode(); carry = 0
2while l1 or l2 or carry:
3 s = (l1.val if l1 else 0) + (l2.val if l2 else 0) + carry
4 carry, digit = divmod(s, 10)
5 tail.next = ListNode(digit); tail = tail.next
6 l1, l2 = l1 and l1.next, l2 and l2.next
7return dummy.next易错点
- 错误写法:循环只写 while l1 and l2 → 正确写法:while l1 or l2 or carry(不等长、或最高位还有进位时会漏算)
- 错误写法:忘了最后的进位 → 正确写法:carry 也作为循环条件(如 5+5=10,最后要补一个 1 节点)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。