美文网首页leetcode Top100
23. 合并K个升序链表

23. 合并K个升序链表

作者: Awecoder | 来源:发表于2022-03-22 22:56 被阅读0次

    题目

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

    输入: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
    时间复杂度:优先队列插入和删除时间成本是logk,最多kn个点,也就是2kn次,因此总时间复杂度是nlogk

    Java优先队列内部是最小堆实现的。

    class Solution {
        PriorityQueue<Element> queue = new PriorityQueue<>();
    
        public ListNode mergeKLists(ListNode[] lists) {
            // 初始化优先队列
            for (ListNode node : lists) {
                if (node != null) {
                    queue.add(new Element(node));
                }
            }
            // 弹出最小元素,并入队新元素
            ListNode pre = new ListNode(-1);
            ListNode cur = pre;
            while (!queue.isEmpty()) {
                Element minE = queue.poll();
                if (minE.listNode.next != null) {
                    queue.add(new Element(minE.listNode.next));
                }
                // 下一个值
                cur.next = minE.listNode;
                // 指针后移
                cur = cur.next;
            }
            return pre.next;
        }
    
        /**
         * 可以比较的元素
         */
        class Element implements Comparable<Element> {
            ListNode listNode;
    
            Element(ListNode listNode) {
                this.listNode = listNode;
            }
    
            @Override
            public int compareTo(Element o) {
                return this.listNode.val - o.listNode.val;
            }
        }
    }
    

    分治思想实现

    几个有序的链表,第一时间没想起用分治来解决,真的是罪过。。
    分治很好实现,不断拆分递归,基于链表两两合并

    空间复杂度:分治使用到虚拟机栈,logk
    时间复杂度:比较两个链表是2n,也就是n。需要logk次,因此复杂度是nlogk。
    与上面的优先队列差不多。

    class Solution {
    
        public ListNode mergeKLists(ListNode[] lists) {
            return merge(lists, 0, lists.length - 1);
        }
    
        // 分治合并
        public ListNode merge(ListNode[] lists, int left, int right) {
            if (left == right) {
                return lists[left];
            }
            if (left > right) {
                return null;
            }
            int mid = (left + right) >> 1;
            return mergeTwoLists(merge(lists, left, mid), merge(lists, mid + 1, right));
        }
    
        // 两两合并两个相邻链表
        public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
            // 出于性能考虑的话,也可以先判断一次空
            ListNode pre = new ListNode(-1);
            ListNode tail = pre;
            while (list1 != null && list2 != null) {
                if (list1.val <= list2.val) {
                    tail.next = list1;
                    list1 = list1.next;
                } else {
                   tail.next = list2;
                   list2 = list2.next;
                }
                tail = tail.next;
            }
            // 剩余的部分
            tail.next = list1 != null ? list1 : list2;
            return pre.next;
        }
    }
    

    相关文章

      网友评论

        本文标题:23. 合并K个升序链表

        本文链接:https://www.haomeiwen.com/subject/cvvqjrtx.html