【算法--链表题4】23.合并K个升序链表
通俗易懂讲解“合并K个升序链表”算法题目(不使用最小堆)
一、题目是啥?一句话说清
给你K个已经排好序的链表,让你把它们合并成一个新的有序链表。
示例:
- 输入:lists = [[1,4,5],[1,3,4],[2,6]]
- 输出:[1,1,2,3,4,4,5,6]
二、解题核心
使用分治策略,将K个链表两两分组合并,然后再将合并后的结果两两合并,直到最终合并成一个链表。 这就像组织一场多人比赛,先进行小组赛,然后小组胜者再进行比赛,直到决出最终冠军。
三、关键在哪里?(3个核心点)
想理解并解决这道题,必须抓住以下三个关键点:
1. 分治策略(Divide and Conquer)
- 是什么:将大问题分解为小问题,分别解决后再合并结果。
- 为什么重要:直接合并K个链表效率低(O(K²N)),而分治法可以将时间复杂度降低到O(NKlogK),其中N是平均链表长度,K是链表数量。
2. 两两合并的技巧
- 是什么:使用合并两个有序链表的算法作为基础操作。
- 为什么重要:这是分治法的核心操作,需要高效且正确地实现。
3. 分组策略
- 是什么:如何将K个链表合理地分成两组,分别处理。
- 怎么办:通常采用二分法,将链表列表分成前后两半,递归处理。
四、看图理解流程(通俗理解版本)
让我们用 lists = [[1,4,5],[1,3,4],[2,6]] 的例子来可视化分治合并过程:
-
初始状态:有三个链表需要合并
- 链表1: 1→4→5
- 链表2: 1→3→4
- 链表3: 2→6
-
第一层分治:
- 将三个链表分成两组:第一组包含前两个链表,第二组包含最后一个链表
- 递归处理第一组:合并链表1和链表2
- 合并过程:比较1和1→选择1,比较4和3→选择3,比较4和4→选择4,最后接上5
- 结果:1→1→3→4→4→5
- 第二组只有一个链表,直接返回:2→6
-
第二层分治:
- 将第一组的结果(1→1→3→4→4→5)和第二组的结果(2→6)合并
- 合并过程:
- 比较1和2→选择1
- 比较1和2→选择1
- 比较3和2→选择2
- 比较3和6→选择3
- 比较4和6→选择4
- 比较4和6→选择4
- 比较5和6→选择5
- 最后接上6
- 最终结果:1→1→2→3→4→4→5→6
-
结束:返回最终合并后的链表
五、C++ 代码实现(附详细注释)
#include <iostream>
#include <vector>
using namespace std;// 链表节点定义
struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val