【LeetCode 23】力扣困难算法:合并 K 个升序链表 —— “ 优先队列算法 ”

题目:给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。

输入: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

提示:

  • 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

要合并 k 个已排序的链表,我们可以使用优先队列(最小堆)来有效地找到当前最小的元素。这种方法的时间复杂度为 O(N log k),其中 N 是所有链表中节点的总数,k 是链表的数量。

Java 中的优先队列:

在 Java 中,PriorityQueue 类是一个基于优先级的无界队列,使用优先级堆(默认是最小堆)实现。它提供了以下主要操作:

  • offer (E e):向优先队列添加一个元素。

  • poll ():移除并返回优先队列中优先级最高的元素(最小元素)。

  • peek ():返回优先队列中优先级最高的元素但不移除它。

  • Java 的 PriorityQueue 还允许自定义比较器(Comparator),以定义元素的排序规则。

算法步骤:

  1. 创建一个优先队列:优先队列用于存储每个链表的头节点,并按节点的值排序。

  2. 遍历链表:遍历每个链表,将每个链表的头节点添加到优先队列中。

  3. 合并链表:从优先队列中取出最小元素,将其添加到结果链表中,然后更新该节点的 next 指针(如果存在),并将其添加回优先队列。重复此过程,直到优先队列为空。

  4. 返回结果:返回合并后的链表的头节点。

复杂度分析:

  • 时间复杂度:O (N log k),其中 N 是所有链表中节点的总数,k 是链表的数量。这是因为我们需要从优先队列中取出 N 个节点,每次取出操作的时间复杂度为 O(log k)。

  • 空间复杂度:O (k),最坏情况下,优先队列中可能同时存储 k 个链表的头节点。

我的 Java 代码:

/**
 * 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==null || lists.length==0 ){
            return null;
        }
        
        // 步骤1:创建一个优先队列,用于存储每个链表的头节点
        PriorityQueue<ListNode> queue = new PriorityQueue<>((a,b)->(a.val-b.val));
        
        // 步骤2:将每个链表的头节点添加到优先队列中
        for(ListNode list : lists){
            if(list != null){   // 注意要写这个条件!!可能 lists = [[]]
                queue.offer(list);
            }
        }
        
        // 步骤3:从优先队列中取出最小元素,添加到结果链表中
        ListNode dummyHead = new ListNode(0);
        ListNode cur = dummyHead;
        while( !queue.isEmpty() ){
            ListNode min = queue.poll();
            cur.next = min;
            cur = cur.next;  // 指针后移
            if(min.next != null){      // 头结点的下一个结点不为空
                queue.offer(min.next); // 则把下一个结点添加到优先队列
            }
        }
        return dummyHead.next;
    }
}
posted @ 2025-07-30 17:22  junjunyi  阅读(48)  评论(0)    收藏  举报