【LeetCode-面试算法经典-Java实现】【023-Merge k Sorted Lists(合并k个排好的的单链表)】

【023-Merge k Sorted Lists(合并k个排好的的单链表)】


【LeetCode-面试算法经典-Java实现】【所有题目目录索引】

原题

  Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

题目大意

  合并k个排好的的单链表。分析和描述它的复杂性。

解题思路

  使用小顶堆来实现,先将K个链表的头结点入堆,取堆顶元素,这个结点就是最小的,接着让取出的这个结点的下一个结点入堆,再取堆顶元素,其为第二小的结点,一直这样子操作,直到所有的结点都处理完,这样就完成了链表的合并,更多细节请见代码和注释。假设K个链表一共有N个结点,时间复杂度是O(N*log(K)),空间复杂度是O(K)。

代码实现

结点类

public class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }
}

算法实现类

public class Solution {
   public ListNode mergeKLists(ListNode[] lists) {

        // 为空或者没有元素
        if (lists == null || lists.length < 1) {
            return null;
        }

        // 只有一个元素
        if (lists.length == 1) {
            return lists[0];
        }

        // 创建一个小顶堆,并且使用一个匿名内部类作为比较器
        MinHeap<ListNode> minHeap = new MinHeap<ListNode>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                if (o1 == null) {
                    return -1;
                }

                if (o2 == null) {
                    return 1;
                }

                return o1.val - o2.val;
            }
        });

        // 将数组中链表的第一个结点入堆
        for (ListNode node : lists) {
            if (node != null) {
                minHeap.add(node);
            }
        }

        // 头结点,作辅助使用
        ListNode head = new ListNode(0);
        // 当前处理的结点
        ListNode curr = head;

        while (!minHeap.isEmpty()) {
            ListNode node = minHeap.deleteTop();

            // 结点的下一个结点不为空就将下一个结点入堆
            if (node.next != null) {
                minHeap.add(node.next);
            }

            curr.next = node;
            curr = node;
        }

        return head.next;
    }

    /**
     * 小顶堆
     *
     * @param <T>
     */
    private static class MinHeap<T> {
        // 堆中元素存放的集合
        private List<T> items;

        private Comparator<T> comp;

        /**
         * 构造一个椎,始大小是32
         */
        public MinHeap(Comparator<T> comp) {
            this(32, comp);
        }

        /**
         * 造诣一个指定初始大小的堆
         *
         * @param size 初始大小
         */
        public MinHeap(int size, Comparator<T> comp) {
            items = new ArrayList<>(size);
            this.comp = comp;
        }

        /**
         * 向上调整堆
         *
         * @param index 被上移元素的起始位置
         */
        public void siftUp(int index) {
            T intent = items.get(index); // 获取开始调整的元素对象

            while (index > 0) { // 如果不是根元素
                int parentIndex = (index - 1) / 2; // 找父元素对象的位置
                T parent = items.get(parentIndex);  // 获取父元素对象
                if (comp.compare(intent, parent) < 0) { //上移的条件,子节点比父节点小
                    items.set(index, parent); // 将父节点向下放
                    index = parentIndex; // 记录父节点下放的位置
                } else { // 子节点不比父节点小,说明父子路径已经按从小到大排好顺序了,不需要调整了
                    break;
                }
            }

            // index此时记录是的最后一个被下放的父节点的位置(也可能是自身),
            // 所以将最开始的调整的元素值放入index位置即可
            items.set(index, intent);
        }

        /**
         * 向下调整堆
         *
         * @param index 被下移的元素的起始位置
         */
        public void siftDown(int index) {
            T intent = items.get(index);  // 获取开始调整的元素对象
            int leftIndex = 2 * index + 1; // // 获取开始调整的元素对象的左子结点的元素位置

            while (leftIndex < items.size()) { // 如果有左子结点
                T minChild = items.get(leftIndex); // 取左子结点的元素对象,并且假定其为两个子结点中最小的
                int minIndex = leftIndex; // 两个子节点中最小节点元素的位置,假定开始时为左子结点的位置

                int rightIndex = leftIndex + 1;  // 获取右子结点的位置
                if (rightIndex < items.size()) {  // 如果有右子结点
                    T rightChild = items.get(rightIndex);  // 获取右子结点的元素对象
                    if (comp.compare(rightChild, minChild) < 0) {  // 找出两个子节点中的最小子结点
                        minChild = rightChild;
                        minIndex = rightIndex;
                    }
                }

                // 如果最小子节点比父节点小,则需要向下调整
                if (comp.compare(minChild, intent) < 0) {
                    items.set(index, minChild); // 将子节点向上移
                    index = minIndex; // 记录上移节点的位置
                    leftIndex = index * 2 + 1; // 找到上移节点的左子节点的位置
                } else { // 最小子节点不比父节点小,说明父子路径已经按从小到大排好顺序了,不需要调整了
                    break;
                }
            }

            // index此时记录是的最后一个被上移的子节点的位置(也可能是自身),
            // 所以将最开始的调整的元素值放入index位置即可
            items.set(index, intent);
        }

        /**
         * 向堆中添加一个元素
         *
         * @param item 等待添加的元素
         */
        public void add(T item) {
            items.add(item); // 将元素添加到最后
            siftUp(items.size() - 1); // 循环上移,以完成重构
        }

        /**
         * 删除堆顶元素
         *
         * @return 堆顶部的元素
         */
        public T deleteTop() {
            if (items.isEmpty()) { // 如果堆已经为空,就报出异常
                throw new RuntimeException("The heap is empty.");
            }

            T maxItem = items.get(0); // 获取堆顶元素
            T lastItem = items.remove(items.size() - 1); // 删除最后一个元素
            if (items.isEmpty()) { // 删除元素后,如果堆为空的情况,说明删除的元素也是堆顶元素
                return lastItem;
            }

            items.set(0, lastItem); // 将删除的元素放入堆顶
            siftDown(0); // 自上向下调整堆
            return maxItem; // 返回堆顶元素
        }

        /**
         * 判断堆是否为空
         *
         * @return true是空,false否
         */
        public boolean isEmpty() {
            return items.isEmpty();
        }
    }

}

评测结果

  点击图片,鼠标不释放,拖动一段位置,释放后在新的窗口中查看完整图片。

特别说明

欢迎转载,转载请注明出处【http://blog.csdn.net/derrantcm/article/details/47016131

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-10 08:04:40

【LeetCode-面试算法经典-Java实现】【023-Merge k Sorted Lists(合并k个排好的的单链表)】的相关文章

[LeetCode] 23. Merge k Sorted Lists 合并k个有序链表

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 与21. Merge Two Sorted Lists的拓展,这道题要合并k个有序链表,还是可以两两合并. 类似题目: [LeetCode] 21. Merge Two Sorted Lists 合并有序链表 原文地址:https://www.cnblogs.com/lightwindy/p/8512

【LeetCode-面试算法经典-Java实现】【019-Remove Nth Node From End of List(移除单链表的倒数第N个节点)】

[019-Remove Nth Node From End of List(移除单链表的倒数第N个节点)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a linked list, remove the nth node from the end of list and return its head. For example, Given linked list: 1->2->3->4->5, and n = 2. After remo

[Leetcode] Merge k sorted lists 合并k个已排序的链表

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 思路:这题最容易想到的是,(假设有k个链表)链表1.2合并,然后其结果12和3合并,以此类推,最后是123--k-1和k合并.至于两链表合并的过程见merge two sorted lists的分析.复杂度的分析见JustDoIT的博客.算法复杂度:假设每个链表的平均长度是n,则1.2合并,遍历2n个

leetCode 23. Merge k Sorted Lists (合并k个排序链表) 解题思路和方法

Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 思路:此题是由合并两个排序链表演化而来,刚开始,想法比较简单,像求最大公共前缀一样,逐一求解:但是最后超时,所以马上意识到出题方是为了使用归并和分治的方法,故重新写了代码. 代码一(超时未过): /** * Definition for singly-link

[LeetCode]23. Merge k Sorted Lists合并K个排序链表

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. Example: Input: [   1->4->5,   1->3->4,   2->6 ] Output: 1->1->2->3->4->4->5->6 要合并K个排好序的链表,我用的方法是用一个优先队列每次存K个元素在队列中,根据优

23. Merge k Sorted Lists 合并K个有序链表

这道题是21题合并2个有序链表的升级版本,看了许多解题思路: A:直接暴力解锁,全部放进一个堆,然后依次吐出来: B:利用21题的算法,循环一次做两两合并,这样就得到结果:但是时间复杂度有点差: C:利用归并排序思想,进行分治:其实就是利用递归,牺牲空间,提升时间效率: 存在的问题是:看过了许多解答后发现,大家基于的给定数据类型是 List<ListNode>/ArrayList<ListNode>,然后,现在系统更新了,给的数据类型是 ListNode[] lists,所以,我现

【LeetCode-面试算法经典-Java实现】【021-Merge Two Sorted Lists(合并两个排好序的单链表)】

[021-Merge Two Sorted Lists(合并两个排好序的单链表)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. 题目大意 合并两个排序链表并返回一个新的列表.新的链表的

Leetcode:Merge Two Sorted Lists 合并两个有序单链表

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. 代码如下: * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x

[LeetCode]21 Merge Two Sorted Lists 合并两个有序链表

---恢复内容开始--- [LeetCode]21 Merge Two Sorted Lists 合并两个有序链表 Description Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. Example Example: Input: 1->2->4, 1-&g

【LeetCode-面试算法经典-Java实现】【088-Merge Sorted Array(合并排序数组)】

[088-Merge Sorted Array(合并排序数组)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note: You may assume that nums1 has enough space (size that is greater or equal to m +