23 Merge k Sorted Lists

本文介绍了一种使用优先级队列合并K个已排序链表的方法。通过维护一个大小为K的最小堆,每次取出堆顶元素并将其下一个元素重新放入堆中,最终得到一个完整的排序链表。

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

31/05/2017 今天又看了一下这个题,重温了一下PriorityQueue。 这题思路: 每次把PriorityQueue里最小的那个Node撸下来,然后把这个最小Node的next结点加入到PriorityQueue里去。PriorityQueue的意义在于能保证队首永远是最小的Node,后面的顺序每次add/offer都会变,无法保证是按顺序的(堆排序我还需要再复习一遍),但是我们也不需要后面是按顺序的,只需要min heap的堆顶元素就行了。


这题用了堆heap的思想,用的是优先权队列实现的。

   public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) return null;
        PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                //none - descending sort
                return o1.val - o2.val;
            }
        });

        for (ListNode list : lists) {
            if (list != null)
                queue.offer(list);
        }

        ListNode dummy = new ListNode(-1);
        ListNode tail = dummy;
        while (!queue.isEmpty()) {
            tail.next = queue.poll();
            tail = tail.next;

            //把每个链表上的node全撸下来加入到queue,注意这个撸下来的过程可能不是连续的,可能先撸了第一个链表的next就去撸下一个链表了
            if (tail.next != null) {
                queue.offer(tail.next);
            }
        }
        return dummy.next;
    }

复制代码

一开始我不懂为什么这题的参数是一个数组,我以为应该是好几个参数,每个参数是一个list呢。直到看到

            if (tail.next != null) {
                queue.offer(tail.next);
            }
复制代码

我才恍然大悟,每个listNode自身就是一个链表呀。

引用CodeGanker的讲解:

维护一个大小为k的堆,每次取堆顶的最小元素放到结果中,然后读取该元素的下一个元素放入堆中,重新维护好。因为每个链表是有序的,每次又是去当前k个元素中最小的,所以当所有链表都读完时结束,这个时候所有元素按从小到大放在结果链表中。

其实我有点不太懂为什么这k个list要是已经排序好的了,因为这样看来根本不需要啊(我不懂Java的PriorityQueue是不是每次add/offer一个元素就会自动排序一次?如果是的话,那无论怎么插入元素,poll出来的永远是排好序的queue中的最小元素呀。。)

对于复杂度:这个算法每个元素要读取一次,即是k*n次,然后每次读取元素要把新元素插入堆中要logk的复杂度,所以总时间复杂度是O(nklogk)。空间复杂度是堆的大小,即为O(k)。

看来这里的offer/add用的是二分搜索形式。

转载于:https://juejin.im/post/5a3133faf265da432f311fab

To merge k sorted linked lists, one approach is to repeatedly merge two of the linked lists until all k lists have been merged into one. We can use a priority queue to keep track of the minimum element across all k linked lists at any given time. Here's the code to implement this idea: ``` struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; // Custom comparator for the priority queue struct CompareNode { bool operator()(const ListNode* node1, const ListNode* node2) const { return node1->val > node2->val; } }; ListNode* mergeKLists(vector<ListNode*>& lists) { priority_queue<ListNode*, vector<ListNode*>, CompareNode> pq; for (ListNode* list : lists) { if (list) { pq.push(list); } } ListNode* dummy = new ListNode(-1); ListNode* curr = dummy; while (!pq.empty()) { ListNode* node = pq.top(); pq.pop(); curr->next = node; curr = curr->next; if (node->next) { pq.push(node->next); } } return dummy->next; } ``` We start by initializing a priority queue with all the head nodes of the k linked lists. We use a custom comparator that compares the values of two nodes and returns true if the first node's value is less than the second node's value. We then create a dummy node to serve as the head of the merged linked list, and a current node to keep track of the last node in the merged linked list. We repeatedly pop the minimum node from the priority queue and append it to the merged linked list. If the popped node has a next node, we push it onto the priority queue. Once the priority queue is empty, we return the head of the merged linked list. Note that this implementation has a time complexity of O(n log k), where n is the total number of nodes across all k linked lists, and a space complexity of O(k).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值