EASY题LINKEDLISTNEEDREVIEWD

23. Merge k Sorted Lists

2017-03-27  本文已影响55人  DrunkPian0

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用的是二分搜索形式。

上一篇下一篇

猜你喜欢

热点阅读