23. 合并K个升序链表

188 阅读1分钟

题目介绍

力扣23题:leetcode-cn.com/problems/me…

image.png

分析

合并k个有序链表的逻辑类似合并两个有序链表,难点在于,如何快速得到k个节点中的最小节点,接到结果链表上?

这里我们就要用到 [优先队列]这种数据结构,把链表节点放入一个最小堆,就可以每次获得k个节点中的最小节点:

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists.length == 0) {
            return null;
        }

        //哨兵节点,指向新链表头节点的上一个节点
        ListNode preHead = new ListNode(-1);
        ListNode pre = preHead;

        //创建优先队列,使用小顶堆
        PriorityQueue<ListNode> pq = new PriorityQueue<>(lists.length , (a,b) -> {
            return a.val - b.val;
        });

        //将k个链表的头节点加入到小顶堆中
        for(ListNode head : lists) {
            if(head != null) {
                //加入优先队列
                pq.add(head);
            }
        }

        while(!pq.isEmpty()) {
            //获取小顶堆最小值,即堆顶元素
            ListNode node = pq.poll();
            pre.next = node;
            if(node.next != null) {
                pq.add(node.next);
            }
            //pre指针不断前进
            pre = pre.next;
        }
        return preHead.next;
    }
}

这个算法是面试常考题,它的时间复杂度是多少呢?

优先队列pq中的元素个数最多是k,所以一次poll或者add方法的时间复杂度是O(logk);所有的链表节点都会被加入和弹出pq所以算法整体的时间复杂度是O(Nlogk),其中k是链表的条数,N是这些链表的节点总数