【LeetCode刷题(困难程度)】23. 合并K个升序链表

这篇博客介绍了如何合并多个已排序的链表。首先,通过归并排序的思路,将链表两两合并,然后不断递归直到只剩一个链表。此外,还提供了使用小顶堆的方法,将链表节点放入堆中,每次取出最小节点并连接,最后得到合并后的有序链表。这两种方法分别具有不同的时间复杂度。
摘要由CSDN通过智能技术生成

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

 

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:

输入:lists = []
输出:[]
示例 3:

输入:lists = [[]]
输出:[]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

思路1:先从合并两个有序列表开始找到灵感,我们可以利用归并排序的思想,将每个列表数组先进行分治,再进行归并。

代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode* res = nullptr;
        if(lists.size() == 0)
            return res;
        return MergeSort(lists,0,lists.size() - 1);
    }
    //归并算法 将链表个数不断的分到只有两个两个合并
    ListNode* MergeSort(vector<ListNode*>& lists,int left,int right)
    {
        if(left == right)
            return lists[left];
        int mid = (left + right) >> 1;
        ListNode*temp_left = MergeSort(lists,left,mid);
        ListNode* temp_right = MergeSort(lists,mid + 1,right);
        ListNode* res = merge(temp_left,temp_right);
        return res;
    }
    //合并两个有序链表
    ListNode* merge(ListNode* l1,ListNode* l2)
    {
        ListNode* dummyHead = new ListNode(-1);
        ListNode* cur = dummyHead;
        while(l1 != nullptr && l2 != nullptr)
        {
            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;
        if(l2)
            cur->next = l2;
        return dummyHead->next;
    }
};

时间复杂度: k为链表的组数。

O(kn×log k)

思路二:使用堆实现。我们可以构建一个小顶堆,存储链表节点,将每个链表的第一个节点都加入该堆,然后再取出堆顶,取出堆顶之后将该链表的下一节点加入堆中,重复这一过程直到堆为空。

代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    struct
    {
        bool operator()(ListNode* a,ListNode* b)
        {
            return a->val > b->val;
        }
    }cmp;
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size() == 0)
            return nullptr;
        priority_queue<ListNode*,vector<ListNode*>,decltype(cmp)> temp;

        //建立大小为k的小根堆
        for(auto elem : lists)
        {
            if(elem)
                temp.push(elem);
        }

        //使用哑结点
        ListNode* dummyHead = new ListNode(-1);
        ListNode* cur = dummyHead;

        //如果链表组有k个那么 堆的大小也为k个
        //开始出队
        while(!temp.empty())
        {
            ListNode* top = temp.top();//取出最小的数值
            temp.pop();
            cur->next = top;//将链表链接上
            cur = top;//转至下一节点
            if(top->next)
            {
                temp.push(top->next);//取出当前组链表的下一个节点加入堆
            }
        }
        return dummyHead->next;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值