LeetCode 23. Merge k Sorted Lists

问题描述

  • 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

问题分析

  • 该题是 LeetCode 21. Merge Two Sorted Lists 的进阶题目。以下介绍的两种方法也是基于 21 合并的方法提出的。

    • 合并两条有序链表时,用的是双指针法,如果一个找到了,该指针右移。所以可以用一种类似于 k指针的方法,先将 k条链表的头部添加进一个小根堆,每次将堆顶元素出堆,然后将该出堆元素的下一个节点入堆。这样利用最小堆每次都能得到最小值的特点,便实现了一种k指针的作用。
  • 分治法
    • 类似于归并排序
      • :将前 k/2 条链表合并成一条有序链表 p1,将后 k/2条链表合并成一条有序链表 p2。
      • :将有序链表p1,p2合并
  • 两种方法都是 O(NlogK),如果N为所有节点的个数,但是分治法要比堆法更加快。在空间上来看,堆法是O(K),分治法只是O(log N)

经验教训

  • 如果对一个数据集,涉及到不断的插入删除,而且要求实时更新最大值或者最小值,那么肯定是堆

代码实现

    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        //建立一个最小堆,根据节点的val进行排序
        PriorityQueue<ListNode> minHeap = new PriorityQueue<>(new Comparator<ListNode>(){
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        //初始化将k条链表的头结点(若不为空)入堆
        for (int i = 0; i < lists.length; i++) {
            if (lists[i] != null) {
                minHeap.add(lists[i]);
            }
        }
        //每次都将堆顶出堆,然后将出堆元素的下一个节点(如果存在)入堆
        while(! minHeap.isEmpty()) {
            ListNode curNode = minHeap.poll();
            if (curNode.next != null) {
                minHeap.add(curNode.next);
            }
            tail.next = curNode;
            tail = tail.next;
        }
        return dummy.next;
    }
  • 分治法
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        return mergeKLists(lists, 0, lists.length - 1);
    }

    //将lists[begin...end]合并成一条有序链表
    public ListNode mergeKLists(ListNode[] lists, int begin, int end) {
        //base case
        if (begin == end) {
            return lists[begin];
        }
        int mid = begin + (end - begin) / 2;
        // 对 begin ~ mid 进行合并成 p1
        ListNode p1 = mergeKLists(lists, begin, mid);
        // 对 mid + 1 ~ end 进行合并成 p2
        ListNode p2 = mergeKLists(lists, mid + 1, end);
        //p1 p2 合并
        return mergeSortedList(p1, p2);
    }

    //合并两条有序链表
    public ListNode mergeSortedList(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val > l2.val) {
                tail.next = l2;
                l2 = l2.next;
            }else {
                tail.next = l1;
                l1 = l1.next;
            }
            tail = tail.next;
        }
        tail.next = l1 == null ? l2 : l1;
        return dummy.next;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值