题解 | #合并k个已排序的链表#

合并k个已排序的链表

https://www.nowcoder.com/practice/65cfde9e5b9b4cf2b6bafa5f3ef33fa6

合并k个已排序的链表

目标

我们需要把很多条按从小到大排列的珠子串(链表)合并成一条新的珠子串,这条新的珠子串也要按从小到大的顺序排列。

示例

假设我们有三条珠子串:

  • 第一条珠子串:1 → 2
  • 第二条珠子串:1 → 4 → 5
  • 第三条珠子串:6

我们要把这三条珠子串合并成一条新的珠子串,这条珠子串也要按从小到大的顺序排列。

解释步骤

1. 准备一个“假头”珠子

我们先在新珠子串的最前面放一个“假头”珠子,这个珠子实际上不参与最终的珠子串,但可以帮助我们更容易地开始合并。

ListNode dummy = new ListNode(0); // “假头”珠子
ListNode tail = dummy; // 用来记录新珠子串的最后一个珠子

2. 创建一个“魔法盒子”

想象一下,我们有一个“魔法盒子”,这个盒子可以自动把珠子按从小到大的顺序排好。这个“魔法盒子”其实就是一个叫做“优先队列”的工具。

PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);

3. 把每条珠子串的第一个珠子放进“魔法盒子”

我们从每条珠子串的开头开始,把每条珠子串的第一个珠子放进“魔法盒子”里。

for (ListNode list : lists) {
    if (list != null) {
        pq.add(list); // 把第一个珠子放进去
    }
}

4. 从“魔法盒子”里拿出最小的珠子

我们不断地从“魔法盒子”里拿出最小的珠子,然后把这个珠子放到新珠子串里。

while (!pq.isEmpty()) {
    // 从“魔法盒子”里拿出最小的珠子
    ListNode minNode = pq.poll();

    // 把这个珠子放到新珠子串里
    tail.next = minNode;
    tail = tail.next;

    // 如果这个珠子后面还有珠子,就把后面的珠子也放进“魔法盒子”
    if (minNode.next != null) {
        pq.add(minNode.next);
    }
}

5. 返回新珠子串的头珠子

最后,我们返回新珠子串的第一个珠子(实际上是“假头”珠子的下一个珠子)。

return dummy.next;

示例解析

假设我们有以下三条珠子串:

  • 第一条珠子串:1 → 2
  • 第二条珠子串:1 → 4 → 5
  • 第三条珠子串:6
  1. 初始化:
  2. 创建“假头”珠子 dummy。
  3. 创建“魔法盒子” pq。
  4. 把每条珠子串的第一个珠子放进“魔法盒子”:1, 1, 6。
  5. 不断从“魔法盒子”里拿出最小的珠子:
  6. 取出最小珠子 1,放到新珠子串里,然后检查是否有下一个珠子,如果有则放进“魔法盒子”。
  7. 再次取出最小珠子 1,放到新珠子串里,然后检查是否有下一个珠子,如果有则放进“魔法盒子”。
  8. 取出最小珠子 2,放到新珠子串里,然后检查是否有下一个珠子,如果没有则继续。
  9. 取出最小珠子 4,放到新珠子串里,然后检查是否有下一个珠子,如果有则放进“魔法盒子”。
  10. 取出最小珠子 5,放到新珠子串里,然后检查是否有下一个珠子,如果没有则继续。
  11. 取出最小珠子 6,放到新珠子串里,然后检查是否有下一个珠子,如果没有则继续。
  12. 返回结果:
  13. 返回合并后的珠子串的头珠子:{1, 1, 2, 4, 5, 6}。

这样,我们就得到了一条新的按从小到大排列的珠子串。

最后附上完整代码

import java.util.PriorityQueue;

public class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        // 创建一个优先队列,按照节点值从小到大排序
        PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);

        // 初始化:将所有非空链表的头节点加入优先队列
        for (ListNode list : lists) {
            if (list != null) {
                pq.add(list);
            }
        }

        // 创建虚拟头节点简化边界处理
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;

        // 只要优先队列不为空,就继续合并
        while (!pq.isEmpty()) {
            // 取出当前最小的节点
            ListNode minNode = pq.poll();
            // 将该节点加入到结果链表中
            tail.next = minNode;
            tail = tail.next;
            // 如果该节点有下一个节点,将下一个节点加入优先队列
            if (minNode.next != null) {
                pq.add(minNode.next);
            }
        }

        // 返回合并后的链表头节点
        return dummy.next;
    }
}

#牛客创作赏金赛#
小学生都能看懂的算法 文章被收录于专栏

主要面向小白的算法文章。以小学生都能看懂为目标而编写,顺便巩固下自己。

全部评论

相关推荐

联通 技术人员 总包不低于12
点赞 评论 收藏
分享
微风不断:兄弟,你把四旋翼都做出来了那个挺难的吧
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务