抖音高频编程考题:合并 K 个升序链表 (困难)

题目描述

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

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

示例 2:输入:lists = [] 输出:[]

示例 3:输入:lists = [[]] 输出:[]

提示:

  • 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

解题思路

要将多个有序链表合并成一个有序链表,可以使用优先队列(最小堆)来实现,这样能够有效地将多个链表中的最小节点逐步合并,最终形成一个有序的链表。

  1. 使用优先队列来存储每个链表的头节点。优先队列能够保证每次从多个链表中取出的节点都是当前最小的节点。
  2. 将每个链表的头节点加入优先队列。
  3. 每次从优先队列中取出最小节点,并将该节点的下一个节点加入优先队列。
  4. 重复上述步骤,直到所有节点都被处理完。

复杂度分析

  • 时间复杂度:对于每个节点的插入和删除操作,优先队列的时间复杂度为 O(log k),其中 k 是链表的数量。总的时间复杂度为 O(N log k),其中 N 是所有节点的总数。

  • 空间复杂度:空间复杂度主要取决于优先队列的存储空间,最坏情况下为 O(k)。

代码实现

package org.zyf.javabasic.letcode.hot100.list;

import org.zyf.javabasic.letcode.list.base.ListNode;

import java.util.PriorityQueue;

/**
 * @program: zyfboot-javabasic
 * @description: 合并 K 个升序链表 (困难)
 * @author: zhangyanfeng
 * @create: 2024-08-22 10:32
 **/
public class MergeKListsSolution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }

        // 创建优先队列,并指定排序规则为节点值的升序
        PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);

        // 将每个链表的头节点加入优先队列
        for (ListNode list : lists) {
            if (list != null) {
                pq.offer(list);
            }
        }

        // 创建一个哨兵节点,方便操作
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;

        // 逐步从优先队列中取出最小节点,加入结果链表
        while (!pq.isEmpty()) {
            ListNode minNode = pq.poll();
            current.next = minNode;
            current = current.next;

            // 如果最小节点有下一个节点,将其加入优先队列
            if (minNode.next != null) {
                pq.offer(minNode.next);
            }
        }

        return dummy.next;
    }

    public static void main(String[] args) {
        MergeKListsSolution solution = new MergeKListsSolution();

        // 示例 1
        ListNode l1 = new ListNode(1);
        l1.next = new ListNode(4);
        l1.next.next = new ListNode(5);

        ListNode l2 = new ListNode(1);
        l2.next = new ListNode(3);
        l2.next.next = new ListNode(4);

        ListNode l3 = new ListNode(2);
        l3.next = new ListNode(6);

        ListNode[] lists = {l1, l2, l3};
        ListNode mergedList = solution.mergeKLists(lists);
        printList(mergedList); // 输出:[1, 1, 2, 3, 4, 4, 5, 6]

        // 示例 2
        ListNode[] emptyLists = {};
        ListNode mergedList2 = solution.mergeKLists(emptyLists);
        printList(mergedList2); // 输出:[]

        // 示例 3
        ListNode[] singleEmptyList = {null};
        ListNode mergedList3 = solution.mergeKLists(singleEmptyList);
        printList(mergedList3); // 输出:[]
    }

    // 打印链表
    public static void printList(ListNode head) {
        while (head != null) {
            System.out.print(head.val + " ");
            head = head.next;
        }
        System.out.println();
    }
}

  具体可见:LeetCode 热题 100 回顾_leetcode热题100-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值