当前位置:首页 > 牛客题解 > 牛客227 算法面试必刷题 合并K个有序链表的完整剖析

牛客227 算法面试必刷题 合并K个有序链表的完整剖析

2天前牛客题解49

截图未命名.jpg 牛客227 算法面试必刷题 合并K个有序链表的完整剖析 牛客227题解 优先队列 链表合并 K路归并 算法优化 C++实现 第1张

一、问题理解

首先,我们需要明确什么是"合并K个有序链表"。给定K个已经按升序排列的链表,我们需要将它们合并成一个新的有序链表。这个问题是经典"合并两个有序链表"问题的扩展,在数据处理、数据库操作等场景中非常常见。

二、解决方案分析

优先队列法:

我们使用优先队列(最小堆)来优化合并过程,这也是上面代码采用的方法。其核心思想是:

  • 每次从K个链表的当前头节点中选出最小的节点

  • 将该节点加入结果链表

  • 将该节点的下一个节点加入比较范围

  • 重复上述过程直到所有节点处理完毕

这种方法的时间复杂度是O(NlogK),空间复杂度是O(K)。

三、完整代码

#include <vector>
#include <queue>
using namespACe std;

// 自定义优先队列比较函数
struct cmp {
    bool operator()(ListNode* a, ListNode* b) {
        return a->val > b->val; // 小顶堆
    }
};

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        // 创建一个优先队列(最小堆)
        priority_queue<ListNode*, vector<ListNode*>, cmp> minHeap;
        
        // 1. 将所有链表的头节点加入堆中
        for (auto list : lists) {
            if (list != nullptr) {
                minHeap.push(list);
            }
        }
        
        // 2. 创建一个哑节点(dummy)作为结果链表的起始点
        ListNode dummy(0);
        ListNode* tail = &dummy;
        
        // 3. 不断从堆中取出最小节点,连接到结果链表
        while (!minHeap.empty()) {
            // 取出当前最小节点
            ListNode* minNode = minHeap.top();
            minHeap.pop();
            
            // 将该节点连接到结果链表
            tail->next = minNode;
            tail = tail->next;
            
            // 如果该节点还有下一个节点,将下一个节点加入堆中
            if (minNode->next != nullptr) {
                minHeap.push(minNode->next);
            }
        }
        
        return dummy.next;
    }
};

四、代码逐行解析

让我们详细解析提供的C++代码

    1.自定义比较函数

struct cmp {
    bool operator()(ListNode* a, ListNode* b) {
        return a->val > b->val; // 小顶堆
    }
};

定义了一个比较结构体,用于优先队列的比较。这里使用">"来创建最小堆。

    2.核心合并函数

ListNode* mergeKLists(vector<ListNode*>& lists)

函数接收一个链表数组作为输入,返回合并后的链表头节点。

    3.初始化优先队列

priority_queue<ListNode*, vector<ListNode*>, cmp> minHeap;

创建了一个最小堆,用于高效获取当前最小节点。

    4.填充初始堆

for (auto list : lists) {
    if (list != nullptr) {
        minHeap.push(list);
    }
}

将所有非空链表的头节点加入堆中。

    5.创建结果链表

ListNode dummy(0);
ListNode* tail = &dummy;

使用哑节点技巧简化链表操作,tail指针用于跟踪结果链表的末尾。

    6.合并过程

while (!minHeap.empty()) {
    ListNode* minNode = minHeap.top();
    minHeap.pop();
    
    tail->next = minNode;
    tail = tail->next;
    
    if (minNode->next != nullptr) {
        minHeap.push(minNode->next);
    }
}
  • 取出堆顶最小节点

  • 将其连接到结果链表

  • 如果该节点有后继节点,将后继节点加入堆中

总结

合并K个有序链表是一个经典算法问题,展示了优先队列(堆)数据结构的强大能力。通过这种方法,我们能够高效地处理多个有序数据流的合并问题。理解这个算法不仅有助于面试准备,更能提升解决实际工程问题的能力。

希望这篇文章能帮助你全面理解合并K个有序链表的原理和实现。建议读者自己动手实现一遍,并尝试不同的测试用例来验证算法的正确性。


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。