合并K个升序链表

140 阅读3分钟

这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

leetcode 合并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 = [[]]
输出:[]

解题:一个链表数组内的链表都是升序的,要将他们合并成一个升序的链表,可以想办法每次获取一个数组内最小的链表节点,既然数组内链表是升序的,那么每次只用获取每个链表头结点,然后取出这些头节点中最小的一个节点,把这个最小节点拼接到结果链表中,最后取完所有节点时,结果链表就是最终合并的升序的链表了。首先创建一个节点值0的链表,一个指针指向这个链表,后面将获取到的最小节点利用指针拼接到这个节点后面,指针再往后移动一个节点,最后只需返回节点0后面的链表就行。由于不知道数组内有多少个节点,所以无法确定从数组取出最小节点的次数,所以先用while循环,然后用两个变量记录最小节点、和这个节点所在链表在数组内的索引,最小节点用于拼接到结果链表后面,这个索引用来去掉这个最小节点,最小节点取出后下次就不能用了,然后就循环数组内的链表,获取每个链表的头结点来和最小节点比较,最终保证取到最小的节点,但当数组内没有节点可取了,那就是合并完了,可以结束while循环,返回最终合并的结果链表即可。

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode resultListNode = new ListNode();
        ListNode node = resultListNode;
        // 每次获取一个最小节点 拼接到结果链表后
        while (true) {
            // 代表最小节点在数组的索引
            int index = -1;
            // 保存当前最小节点
            ListNode minListNode = null;
            // 遍历数组所有链表头结点查找出当前最小节点
            for (int i = 0; i < lists.length; i++) {
                ListNode listNode = lists[i];
                // 如果当前数组内的链表不是空 那就获取节点值和已保存的最小节点值比较 保存两个中较小的节点
                // 如果当前最小节点是空 说明是第一次 那就默认当前链表头结点最小
                if (listNode != null && (minListNode == null || listNode.val < minListNode.val)) {
                    minListNode = listNode;
                    index = i;
                }
            }
            // 都找不到最小节点了,就是找完了-结束
            if (index == -1) {
                break;
            }
            // 拼接上最小节点
            node.next = minListNode;
            node = node.next;
            // 数组内链表后移一个
            lists[index] = lists[index].next;
        }
        return resultListNode.next;
    }


}

或者利用队列,将链表元素添加到排序的队列中,每次取出队列链表元素头结点就是最小节点,省去了比较获取最小节点步骤。

    public ListNode mergeKLists(ListNode[] lists) {
        // 创建自定义排序的队列
        Queue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode l1, ListNode l2) {
                return l1.val - l2.val;
            }
        });

        // 往队列添加元素
        for (ListNode list : lists) {
            if (list == null) {
                continue;
            }
            queue.add(list);
        }

        ListNode resultListNode = new ListNode();
        ListNode node = resultListNode;
        // 取出队列最小节点拼接
        while (!queue.isEmpty()) {
            // 取出最小头节点
            ListNode poll = queue.poll();
            node.next = poll;
            node = node.next;
            // 再把后面节点加回去 如果有的话
            if (poll.next != null) {
                queue.add(poll.next);
            }
        }
        return resultListNode.next;
    }

或者类似于之前两个链表合并的操作,将k个链表拆分,两两合并最终也可以得到合并的升序链表。