每日OJ题_牛客_NC51合并k个已排序的链表_C++_Java

目录

牛客_NC51合并k个已排序的链表

题目解析

C++代码

Java代码


牛客_NC51合并k个已排序的链表

合并k个已排序的链表_牛客题霸_牛客网

描述:

合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。

数据范围:节点总数 0≤n≤5000,每个节点的val满足 ∣val∣<=1000

要求:时间复杂度 O(nlogn)


题目解析

        如果是两个有序链表合并,我们可能会利用归并排序合并阶段的思想:准备双指针分别放在两个链表头,每次取出较小的一个元素加入新的大链表,将其指针后移,继续比较,这样我们出去的都是最小的元素,自然就完成了排序。

        其实这道题我们也可以两两比较,只要遍历链表数组,取出开头的两个链表,按照上述思路合并,然后新链表再与后一个继续合并,如此循环,知道全部合并完成。但是,这样太浪费时间了。既然都是归并排序的思想了,那可不可以直接归并的分治来做,而不是顺序遍历合并链表呢?答案是可以的!

        如果非要按照归并排序的合并思路,双指针不够用,我们可以直接准备kk个指针,每次比较得出kk个数字中的最小值。为了快速比较k个数字得到最小值,可以利用Java提供的PriorityQueue或者C++SLT提供的优先队列实现,它是一种参照堆排序的容器,容器中的元素是有序的,如果是小顶堆,顶部元素就是最小的,每次可以直接取出最小的元素。也就是说每次该容器中有k个元素,我们可以直接拿出最小的元素,再插入下一个元素,相当于每次都是链表的k个指针在比较大小,只移动最小元素的指针。

C++代码

class Solution {
    struct cmp
    {
        bool operator()(ListNode* l1, ListNode* l2)
        {
            return l1->val > l2->val;
        }
    };
  public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>, cmp> heap; // ⼩根堆
        for (auto head : lists)
        {
            if (head != nullptr)
                heap.push(head);
        }
        ListNode* ret = new ListNode(0);
        ListNode* prev = ret;
        while (heap.size())
        {
            ListNode* t = heap.top();
            heap.pop();
            prev = prev->next = t;
            if (t->next != nullptr)
            {
                heap.push(t->next);
            }
        }

        ListNode* tmp = ret->next;
        free(ret);
        return tmp;
    }
};

Java代码

import java.util.*;
/*
 * public class ListNode {
 * int val;
 * ListNode next = null;
 * public ListNode(int val) {
 * this.val = val;
 * }
 * }
 */
public class Solution
{
    public ListNode mergeKLists (ArrayList<ListNode> lists) 
    {
        PriorityQueue<ListNode> heap = new PriorityQueue<>((l1, l2) -> {
            return l1.val - l2.val;
        });
        for(int i = 0; i < lists.size(); i++)
        {
            if(lists.get(i) != null)
            {
                heap.offer(lists.get(i));
            }
        }
        ListNode ret = new ListNode(0);
        ListNode prev = ret;
        while(!heap.isEmpty())
        {
            ListNode t = heap.poll();
            prev = prev.next = t;
            if(t.next != null)
            {
                heap.offer(t.next);
            }
        }
        return ret.next;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GR鲸鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值