力扣23.合并K个升序链表(方法1.拆分为合并两个链表,方法2.优先队列)

题目:

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

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

示例 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 = [[]]
输出:[]
 

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

方法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* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if(list1 == nullptr){
            return list2;
        }
        if(list2 == nullptr){
            return list1;
        }
        ListNode* HEAD = new ListNode(0);
        ListNode* index = HEAD;
        ListNode* p1 = list1;
        ListNode* p2 = list2;
        while(p1 != nullptr && p2 != nullptr){
            if(p1->val > p2->val){
                index->next = p2;
                p2 = p2->next;
            }
            else{
                index->next = p1;
                p1 = p1->next;
            }
            index = index->next;
        }
        if(p1 != nullptr){
            index->next = p1;
        }
        if(p2 != nullptr){
            index->next = p2;
        }
        return HEAD->next;
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size() == 0){
            return nullptr;
        }
        int k = lists.size();
        ListNode* p = nullptr;
        for(int i = 0; i < k; i++){
            p = mergeTwoLists(p, lists[i]);
        }
        return p;
    }
};

讲解:

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

        if(lists.size() == 0){

            return nullptr;

        }

        int k = lists.size();

        ListNode* p = nullptr;

        for(int i = 0; i < k; i++){

            p = mergeTwoLists(p, lists[i]);

        }

        return p;

    }

首先这段代码就是这道题目一进来的地方,首先判断vector数组长度是否为0,其次开始将数组进行合并,下面来着重讲解一下如何合并

 

if(list1 == nullptr){

            return list2;

        }

        if(list2 == nullptr){

            return list1;

        }

        ListNode* HEAD = new ListNode(0);

        ListNode* index = HEAD;

        ListNode* p1 = list1;

        ListNode* p2 = list2;

上来两个if判断来防止出现空指针的出现,其次设计一个需头节点(常规操作),index代表我们需要向哪里合并,p1和p2代表list1和list2

 

while(p1 != nullptr && p2 != nullptr){

            if(p1->val > p2->val){

                index->next = p2;

                p2 = p2->next;

            }

            else{

                index->next = p1;

                p1 = p1->next;

            }

            index = index->next;

        }

后面进入while循环,判断条件是p1和p2指向的节点不能有一个为空(就是至少一条节点遍历结束),进入while,第一个if就是若p1指向的节点的值更大的话,我们将index的next指针指向p2指向的节点 ,然后让p2指针指向下一个节点,else的话同理,同理index也要向后移动。

if(p1 != nullptr){

            index->next = p1;

        }

        if(p2 != nullptr){

            index->next = p2;

        }

        return HEAD->next;

 当代码运行到这里就代表至少一条列表已经遍历结束,换句话说就是若有一条链表没有遍历结束,那么剩下的节点都是更大的节点,所以我们只要将剩下的链表直接接到index后面即可,最后返回需头节点的下一个节点就完成了。

方法2.优先队列

思路:

这道题我们使用优先级队列,但是我们需要自己维护一个比较器来完成,具体的我将在下面的代码讲解里面说明

代码:

/**
 * 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 comp{
        bool operator()(ListNode* a, ListNode* b){
            return a->val > b->val;
        }
    };
    
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size() == 0){
            return nullptr;
        }
        ListNode* HEAD = new ListNode(0);
        ListNode* p = HEAD;
        priority_queue<ListNode*, vector<ListNode*>, comp> pq;
        for(auto it : lists){
            if(it != nullptr){
                pq.push(it);
            }
        }
        while(!pq.empty()){
            ListNode* temp = pq.top();
            pq.pop();
            p->next = temp;
            if(temp->next != nullptr){
                pq.push(temp->next);
            }
            p = p->next;
        }
        return HEAD->next;
    }
};

讲解:

 

struct comp{

        bool operator()(ListNode* a, ListNode* b){

            return a->val > b->val;

        }

    };

这就是我们写的比较器

if(lists.size() == 0){

            return nullptr;

        }

        ListNode* HEAD = new ListNode(0);

        ListNode* p = HEAD;

        priority_queue<ListNode*, vector<ListNode*>, comp> pq;

 首先判断lists的长度是否为0,然后设置一个虚头节点,p指针指向虚头节点,然后设置一个优先级队列pq

for(auto it : lists){

            if(it != nullptr){

                pq.push(it);

            }

        }

 将各个链表的头节点加入优先级队列

while(!pq.empty()){

            ListNode* temp = pq.top();

            pq.pop();

            p->next = temp;

            if(temp->next != nullptr){

                pq.push(temp->next);

            }

            p = p->next;

        }

return HEAD->next;

 进入while循环,判断条件为优先级队列不为空,首先返回优先级队列首个元素(也就是最小的那个节点,因为我们维护的是最小堆)的引用,然后再将其弹出,p的next指针指向刚才取出的节点,然后去判断刚才取出的节点是否有下一个节点,若有,将其加入到优先级队列,这样就保证了我们这个优先级队列中最少有K个元素(K为链表的条数),然后p指针指向下一个节点。最后返回需头节点的下一个节点,结束。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

puzell

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值