mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
1027 字
3 分钟
链表:两数相加
2026-05-11

题目概览#

范围#

来源内容
class011AddTwoNumbers

题型归纳#

题型: 链表模拟加法

适用条件: 两个链表按逆序存储数字,每个节点只表示一位数字。

解法: 从两个链表头节点开始逐位相加,同时维护进位 carry,每一位生成一个新节点。

易错点: 两个链表长度不同、最后还有进位、空指针取值、返回结果链表头节点。

看到”链表逆序存储数字、需要模拟加法”就是这种写法的信号——因为头节点恰好是个位,逆序存储反而省去了反转的麻烦,可以直接从头往后扫。核心做法是逐位求 sum = h1.val + h2.val + carry,当前位取 sum % 10,进位取 sum / 10;最容易出错的是循环条件写成 && 导致漏算较长链表的高位,以及循环结束后忘记补最后一个进位节点。

例题:2. 两数相加#

题目链接

题意#

给定两个非空链表 l1l2,分别表示两个非负整数,数字按逆序存储,每个节点只存一位。把两个数相加后,用同样的逆序链表形式返回结果。

示例#

示例 1:

342 + 465 = 807,链表逆序存储示意

输入: 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]

提示#

  • 每个链表中的节点数在范围 [1, 100]
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零

解法#

核心思路#

这道题本质就是竖式加法,只是数字已经用链表逆序存好了。

因为头节点就是个位,所以可以直接从两个链表头部开始往后走,逐位求和:当前位的结果是 sum % 10,新的进位是 sum / 10,已经为空的链表在后续计算中按 0 处理。

链表逆序存储不是麻烦,而是恩赐——个位在头节点,天然对齐竖式加法的计算顺序,不需要任何反转。

核心模板#

public static ListNode addTwoNumbers(ListNode h1, ListNode h2) {
ListNode ans = null;
ListNode cur = null;
int carry = 0;
for (int sum, val;
h1 != null || h2 != null;
h1 = h1 == null ? null : h1.next,
h2 = h2 == null ? null : h2.next) {
sum = (h1 == null ? 0 : h1.val)
+ (h2 == null ? 0 : h2.val)
+ carry;
val = sum % 10;
carry = sum / 10;
if (ans == null) {
ans = new ListNode(val);
cur = ans;
} else {
cur.next = new ListNode(val);
cur = cur.next;
}
}
if (carry == 1) {
cur.next = new ListNode(1);
}
return ans;
}

变量角色#

h1h2 分别指向两条链表当前正在相加的节点;ans 记住答案链表的头节点,最终返回它;cur 始终指向答案链表的尾节点,每生成一个新节点就跟着往后移动一位——anscur 初始都为 null,第一次生成节点时同时赋值,之后只动 cur,不动 ans

过程拆解#

  1. 逐位求和:每轮取 h1.val(为空按 0)、h2.val(为空按 0)和 carry 求和。
  2. 生成节点val = sum % 10 作为当前节点值,更新 carry = sum / 10
  3. 接入链表:第一个节点同时赋给 anscur,后续接到 cur.next,再移动 cur
  4. 推进指针h1h2 各自向后移动,已为空的继续保持 null
  5. 补进位:循环结束后如果 carry == 1,在 cur 后面补一个值为 1 的节点。

易错点#

  • 第一次创建节点时,anscur 都要赋值;之后只移动 curans 不能动,否则最终找不到链表头。
循环条件写成 && 会漏算高位

错误写法:

while (h1 != null && h2 != null)

为什么错:较短链表走完后循环立即停止,较长链表剩余的高位全部丢失。比如 l1 = [1]l2 = [9,9],正确结果是 [0,0,1],用 && 只会得到 [0]

正确写法:

h1 != null || h2 != null

两条链表都走完才停,已经为空的那条当前位按 0 处理。

循环结束后忘记补进位节点

错误写法:直接 return ans,不检查 carry

为什么错:最高位相加可能产生进位。比如 l1 = [9]l2 = [9],当前位结果是 8carry = 1,正确答案是 [8,1],漏掉进位会返回 [8]

正确写法:

if (carry == 1) {
cur.next = new ListNode(1);
}
口诀

|| 控制循环,空链表按 0,循环后补进位。

复杂度#

  • 时间复杂度:O(max(n, m))nm 分别是两个链表的长度
  • 空间复杂度:O(max(n, m)),答案链表需要保存相加结果
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

链表:两数相加
https://github.com/algorithmzuo/algorithm-journey/tree/main/src/class011
作者
黎明
发布于
2026-05-11
许可协议
MIT

部分信息可能已经过时

目录