合并 K 个升序链表

cpp 复制代码
class Solution {
public:
    // 主函数:负责启动分治过程
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        // 1. 如果列表为空,直接返回空(防止空数组报错)
        if (lists.empty()) return nullptr;
        // 2. 调用分治函数,范围从 0 到最后一个索引
        return solve(lists, 0, lists.size() - 1);
    }

private:
    // 分治函数:负责把 K 个链表不断二分
    ListNode* solve(vector<ListNode*>& lists, int l, int r) {
        // 3. 递归终止:如果区间里只有一个链表,直接返回它
        if (l == r) return lists[l];
        // 4. 计算中点,>> 1 相当于除以 2(位运算更快)
        int mid = (l + r) >> 1;
        // 5. 递归处理左边,递归处理右边,并把两边的结果通过 merge 函数合并
        return merge(solve(lists, l, mid), solve(lists, mid + 1, r));
    }

    // 核心合并函数:合并两个有序链表(递归版)
    ListNode* merge(ListNode* a, ListNode* b) {
        // 6. 如果 a 空了,返回 b;如果 b 空了,返回 a(谁不空回谁)
        if (!a || !b) return a ? a : b;

        // 7. 如果 a 节点的值比较小
        if (a->val < b->val) {
            // 8. 让 a 的下一个位置去接"剩下的节点合并后的结果"
            a->next = merge(a->next, b);
            // 9. 选了 a 作为当前最小,返回 a
            return a;
        } else {
            // 10. 如果 b 的值较小,同理让 b 的下一个位置去接合并结果
            b->next = merge(a, b->next);
            // 11. 选了 b 作为当前最小,返回 b
            return b;
        }
    }
};

假设我们的 lists 中有 4个小链表

  • L0 : [1, 4]

  • L1 : [2, 6]

  • L2 : [0, 8]

  • L3 : [3, 7]


第一阶段:分治拆解 (solve 函数)

分治像一棵倒置的树,先把问题不断对半劈开。

  1. 第一层solve(0, 3)

    • 计算 mid = 1

    • 拆分为左边 solve(0, 1) 和右边 solve(2, 3)

  2. 第二层(左)solve(0, 1)

    • 计算 mid = 0

    • 拆分为 solve(0, 0)(直接返回 L0 )和 solve(1, 1)(直接返回 L1)。

  3. 第二层(右)solve(2, 3)

    • 计算 mid = 2

    • 拆分为 solve(2, 2)(直接返回 L2 )和 solve(3, 3)(直接返回 L3)。


第二阶段:递归合并 (merge 函数)

现在开始从底层向上"两两决斗"合并。

1. 合并 L0 [1, 4] 和 L1 [2, 6]
  • 比较 1 和 2 :1 小,选 1。1 的后面去接 merge(L0的4, L1的2)

  • 比较 4 和 2 :2 小,选 2。2 的后面去接 merge(L0的4, L1的6)

  • 比较 4 和 6 :4 小,选 4。4 的后面去接 merge(null, L1的6)

  • 收尾:遇到 null,直接接上 6。

  • 结果 (La)[1, 2, 4, 6]

2. 合并 L2 [0, 8] 和 L3 [3, 7]
  • 同理,经过比较:0 < 3,3 < 7,7 < 8。

  • 结果 (Lb)[0, 3, 7, 8]


第三阶段:终极对决 (La 和 Lb 合并)

这是最后一步:merge(La, Lb),即合并 [1, 2, 4, 6][0, 3, 7, 8]

  1. 比较 1 和 00 胜出。结果链表:0 -> ...

  2. 比较 1 和 31 胜出。结果链表:0 -> 1 -> ...

  3. 比较 2 和 32 胜出。结果链表:0 -> 1 -> 2 -> ...

  4. 比较 4 和 33 胜出。结果链表:0 -> 1 -> 2 -> 3 -> ...

  5. 比较 4 和 74 胜出。结果链表:0 -> 1 -> 2 -> 3 -> 4 -> ...

  6. 比较 6 和 76 胜出。结果链表:0 -> 1 -> 2 -> 3 -> 4 -> 6 -> ...

  7. 收尾La 已经空了,把 Lb 剩下的 [7, 8] 直接贴在后面。

最终冠军[0, 1, 2, 3, 4, 6, 7, 8]


总结这个过程的记忆点

  • Solve 是"向下扎根":直到看到单个链表。

  • Merge 是"向上开花":把拿到的两个链表像拉拉链一样合起来。

  • 递归的魅力:你不需要管中间有多少层,你只需要写好"两个怎么合",递归会自动帮你处理剩下的 K-2 个。

相关推荐
airuike1233 分钟前
高性能MEMS IMU:机器人自主运动的核心感知中枢
人工智能·算法·机器人
郝学胜-神的一滴6 分钟前
PyTorch张量维度操控:transpose与permute深度拆解与实战指南
人工智能·pytorch·python·深度学习·算法·机器学习
未来之窗软件服务12 分钟前
SenseVoicecpp ggml-cann.cpp大模型[AI人工智能(七十六)]—东方仙盟
人工智能·算法·sensevoice·仙盟创梦ide·东方仙盟
Trouvaille ~26 分钟前
零基础入门 LangChain 与 LangGraph(一):理解大模型、提示词、Embedding 和接入方式
算法·langchain·大模型·embedding·rag·langgraph·llm应用
xiaoye-duck27 分钟前
《算法题讲解指南:动态规划算法--简单多状态dp问题》--17.买卖股票的最佳时机III,18.买卖股票的最佳时机IV
c++·算法·动态规划
老四啊laosi27 分钟前
[双指针] 5. 有效三角形的个数
算法·leetcode·有效三角形的个数
少许极端28 分钟前
算法奇妙屋(三十九)-贪心算法学习之路 6
java·学习·算法·贪心算法
编程之升级打怪38 分钟前
有难度的关键算法
算法
wangchunting38 分钟前
数据结构-图
数据结构·算法
tyler_download42 分钟前
揉扁搓圆transformer架构:模型参数的初始化算法.
深度学习·算法·transformer