🔗 链表相加算法 | [算法]-[中级]-[链表]
▶ JDK8+ | ⏱️ O(max(M,N))
问题描述
给定两个非空链表,分别表示两个非负整数,满足:
- 数字逆序存储(头节点是个位)
- 每个节点只存储一位数字
请将两数相加,返回相同形式的链表
示例:
输入:l1 = [2,4,3], l2 = [5,6,4] → 342 + 465
输出:[7,0,8] → 807
核心解法
迭代解法(推荐)
/**
* 两数链表相加方法
* @param l1 第一个链表,表示第一个数字(逆序)
* @param l2 第二个链表,表示第二个数字(逆序)
* @return 返回相加结果的链表(逆序)
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0); // 虚拟头节点(简化操作)
ListNode cur = dummy;
int carry = 0; // 进位值
// 三条件确保完全处理:链表未结束或仍有进位
while (l1 != null || l2 != null || carry != 0) {
int sum = carry; // 从进位开始累加
// 安全获取链表值(空则取0)
if (l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if (l2 != null) {
sum += l2.val;
l2 = l2.next;
}
carry = sum / 10; // 计算新进位
cur.next = new ListNode(sum % 10); // 创建结果节点
cur = cur.next; // 移动指针
}
return dummy.next; // 返回真实头节点
}
关键技巧
-
虚拟头节点(dummy):
- 避免空链表特殊处理
- 统一节点添加逻辑
- [最佳实践] 链表操作常用技巧
-
循环三条件:
while (l1 != null || l2 != null || carry != 0)- 确保链表不等长时仍能计算
- 单独处理最后进位(如:9+1=10)
- [注意] 三条件缺一不可,确保完整性
-
安全取值:
// [防御式编程] 空值安全处理 if (l1 != null) sum += l1.val; if (l2 != null) sum += l2.val;
复杂度分析
| 维度 | 复杂度 | 说明 |
|---|---|---|
| 时间 | O(max(M,N)) | 遍历较长链表 |
| 空间 | O(max(M,N)) | 新建结果链表 |
边界处理
graph LR
A[开始] --> B{双链表存在?}
B -->|是| C[计算节点和+进位]
B -->|否| D[检查进位]
C --> E[创建新节点]
E --> F[移动所有指针]
F --> B
D --> |进位>0| G[添加新节点]
D --> |进位=0| H[结束]
G --> H
特殊测试用例
-
进位传递:
99 + 1 = 100→ 输入:[9,9] + [1],输出:[0,0,1] -
不等长链表:
123 + 45678 = 45801→ 输入:[3,2,1] + [8,7,6,5,4] -
零值处理:
0 + 0 = 0→ 输入:[0] + [0],输出:[0]
优化与扩展
递归实现(简洁但不推荐)
/**
* 递归方式实现两数链表相加
* @param l1 第一个链表
* @param l2 第二个链表
* @param carry 进位值
* @return 返回相加结果的链表
*/
public ListNode addTwoNumbersRecursive(ListNode l1, ListNode l2, int carry) {
// [警告] 递归可能导致栈溢出,不适用于长链表
if (l1 == null && l2 == null && carry == 0) {
return null;
}
int sum = carry;
if (l1 != null) sum += l1.val;
if (l2 != null) sum += l2.val;
ListNode result = new ListNode(sum % 10);
result.next = addTwoNumbersRecursive(
l1 != null ? l1.next : null,
l2 != null ? l2.next : null,
sum / 10
);
return result;
}
大数加法关联
// [关联算法] 字符串大数加法
public String addStrings(String num1, String num2) {
StringBuilder res = new StringBuilder();
int i = num1.length() - 1, j = num2.length() - 1;
int carry = 0;
while (i >= 0 || j >= 0 || carry != 0) {
int x = i >= 0 ? num1.charAt(i) - '0' : 0;
int y = j >= 0 ? num2.charAt(j) - '0' : 0;
int sum = x + y + carry;
res.append(sum % 10);
carry = sum / 10;
i--; j--;
}
return res.reverse().toString();
}
学习价值
- ✅ 链表基础操作:指针移动+节点创建
- ✅ 进位处理模式:大数运算通用方法
- ✅ 边界思维训练:空指针/不等长/进位传递
技术决策树
相关题目
🔗 相关题目:
🚀 效率工具:
💡 面试技巧:先解释虚拟头节点作用,再手写代码,最后用测试用例验证边界
▶ 扩展问题:如何处理两个链表正序存储数字的情况?(提示:考虑栈或链表反转)
链表入门:两个链表相加算法解析
419

被折叠的 条评论
为什么被折叠?



