LeetCode 23. 合并 K 个升序链表(分治 + 链表归并)
一、题目描述
给你一个链表数组,每个链表都已经按照升序排列,请将所有链表合并成一条升序链表,并返回合并后的链表头节点。
示例
python
输入:
lists = [[1,4,5],[1,3,4],[2,6]]
输出:
[1,1,2,3,4,4,5,6]
二、最容易想到的方法
最直接的方法是顺序合并:
text
先合并第1条和第2条链表
再和第3条链表合并
再和第4条链表合并......
假设:
- 一共有 k 条链表
- 每条链表平均长度为 n
时间复杂度:
text
O(k²n)
当链表数量较多时,效率比较低。
三、最优思路:分治(归并排序思想)
归并排序的核心思想:
大问题拆成小问题,小问题解决后再合并。
例如:
text
L1 L2 L3 L4 L5 L6
先拆成:
text
L1 L2 L3 L4 L5 L6
继续拆:
text
L1 L2 L3 L4 L5 L6
最后不断合并:
text
(L1+L2) + (L3)
(L4+L5) + (L6)
最终得到整个结果。
四、子问题:合并两个升序链表
这是经典题《合并两个有序链表》的做法。
核心思路
- 两个指针分别指向两条链表;
- 每次选择较小节点接到结果链表后面;
- 某条链表遍历结束后,直接把另一条链表剩余部分接到尾部。
代码
python
def mergeTwoLists(l1, l2):
dummy = ListNode()
cur = dummy
while l1 and l2:
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
if l1:
cur.next = l1
else:
cur.next = l2
return dummy.next
五、分治递归
定义递归函数:
python
merge(left, right)
表示:
合并
lists[left:right+1]区间内所有链表。
终止条件
python
if left == right:
return lists[left]
递归拆分
python
mid = (left + right) // 2
left_list = merge(left, mid)
right_list = merge(mid + 1, right)
return mergeTwoLists(left_list, right_list)
六、完整代码
python
from typing import List, Optional
class Solution:
def mergeKLists(
self,
lists: List[Optional[ListNode]]
) -> Optional[ListNode]:
if not lists:
return None
def mergeTwoLists(l1, l2):
dummy = ListNode()
cur = dummy
while l1 and l2:
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
if l1:
cur.next = l1
else:
cur.next = l2
return dummy.next
def merge(left, right):
if left == right:
return lists[left]
mid = (left + right) // 2
left_list = merge(left, mid)
right_list = merge(mid + 1, right)
return mergeTwoLists(
left_list,
right_list
)
return merge(0, len(lists) - 1)
七、复杂度分析
时间复杂度
text
O(kn × logk)
每一层需要遍历所有节点,共有 logk 层。
空间复杂度
text
O(logk)
主要来自递归调用栈。
八、高频易错点
1、返回值写错
错误:
python
return dummy
正确:
python
return dummy.next
2、参数类型搞混
python
merge()
接收的是数组下标。
python
mergeTwoLists()
接收的是链表头节点。
3、忘记接收递归返回值
错误:
python
merge(left, mid)
merge(mid + 1, right)
正确:
python
left_list = merge(left, mid)
right_list = merge(mid + 1, right)
九、一句话总结
合并 K 个链表的本质,就是利用分治思想,把问题不断拆成「合并两个有序链表」。