欢迎来到李耶的频道【LeetCode面试题】。
合并两个有序链表
题目
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
输入:l1 = [], l2 = []
输出:[]
输入:l1 = [], l2 = [0]
输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50] -100 <= Node.val <= 100l1和l2均按 非递减顺序 排列
解法一:迭代(哑结点)
思路:使用哑结点简化边界处理。同时遍历两个链表,比较当前节点的值,将较小节点接在新链表后面,直到其中一个链表为空,再将剩余部分直接拼接。
javascript
function mergeTwoLists(l1, l2) {
const dummy = new ListNode(0);
let current = dummy;
while (l1 !== null && l2 !== null) {
if (l1.val <= l2.val) {
current.next = l1;
l1 = l1.next;
} else {
current.next = l2;
l2 = l2.next;
}
current = current.next;
}
// 拼接剩余部分
current.next = l1 !== null ? l1 : l2;
return dummy.next;
}
- 时间复杂度 / 空间复杂度:O(m + n) / O(1),其中 m、n 分别为两个链表的长度
- 优势:只需一次遍历,空间 O(1),是面试中最推荐的写法
解法二:递归
思路 :比较两个链表头节点的值,较小者作为合并后链表的头节点,其 next 指向剩余部分的合并结果。递归终止条件为某个链表为空。
javascript
function mergeTwoLists(l1, l2) {
if (l1 === null) return l2;
if (l2 === null) return l1;
if (l1.val <= l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
- 时间复杂度 / 空间复杂度:O(m + n) / O(m + n)(递归调用栈)
- 优势:代码简洁优雅,体现递归思想
- 劣势:递归深度可能较大,空间复杂度 O(m+n),面试中可作为补充解法
解法对比
| 解法 | 时间 / 空间复杂度 | 优势 | 推荐指数 |
|---|---|---|---|
| 迭代(哑结点) | O(m+n) / O(1) | 空间最优,边界处理简洁 | ⭐⭐⭐⭐⭐ |
| 递归 | O(m+n) / O(m+n) | 代码优雅,易于理解 | ⭐⭐⭐⭐ |
扩展题
- 合并 K 个升序链表:给定一个链表数组,每个链表按升序排列,将所有链表合并为一个升序链表。
- 合并两个有序数组:将两个有序数组合并为一个有序数组,要求原地修改。
- 排序链表:在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
"二人同心,其利断金。" ------ 《周易·系辞上》
关注李耶,每天一道面试题,一起卷起来 🔥