20200712——合并k个有序链表

合并k个有序链表 leetcode23

联想

  • 合并2个有序链表

  • 8赛道跑马

思路1

  • 维护一个大小为k的数字,存储链表头。
  • 对链表头元素进行冒泡,得到最小的元素,取出,放到结果链表resList
  • 将最小元素的后一个节点放入数组,重新冒泡一次,得到新的最小元素,放入resList。
  • 重复第3步,若有链表排完了,置为null,放到数组末尾(可以维护一个数组的有效大小arrRealSize)

复杂度分析

  • 时间复杂度

每次冒泡k,取出一个元素。一共n个元素,那么应该是O(nk)

  • 空间复杂度
    不考虑原始链表和结果链表,维护一个k的数组,应该是O(k)

思路2

对思路1稍稍改进
先进行一次排序O(klogk)
后续,只用对最小的元素的后续元素进行一次冒泡,那么平均复杂度可能大概是O(k/2)

O(k(logk+n/2))

public ListNode mergeKLists(ListNode[] lists) {
        int arrRealLength = lists.length;
        if (arrRealLength<=0) return null;
        //检查一遍数组元素是否为null
        for (int i = 0; i < arrRealLength; i++) {
            if (lists[i]==null){
                swap(lists,i,arrRealLength-- - 1);
                i--;
            }
        }
        for (int i = 0; i < arrRealLength; i++) {
            bubbleSort(lists,0,arrRealLength-1-i,false);
        }
        if (lists[0]==null) return null;
        //第1个元素,新链表的头
        ListNode newHead = new ListNode(lists[0].val);
        ListNode node = newHead;
        lists[0] = lists[0].next;
        if (lists[0]==null){
            swap(lists,0,arrRealLength-- - 1);
        }
        while (arrRealLength>0){
            bubbleSort(lists,0,arrRealLength-1,true);
            node.next = lists[0];
            node = node.next;
            lists[0] = lists[0].next;
            if (lists[0]==null){
                swap(lists,0,arrRealLength-- - 1);
            }
        }
        return newHead;

    }
    public void bubbleSort(ListNode[] lists,int start,int end,boolean isBreak){
        for (int i = start; i <end ; i++) {
            if (lists[i].val>lists[i+1].val){
                swap(lists,i,i+1);
            }else if (isBreak){
                break;
            }
        }
    }
    public void swap(ListNode[] lists,int i,int j){
        ListNode temp = lists[i];
        lists[i]= lists[j];
        lists[j] = temp;
    }

leetcode结果:

554ms 
41.6MB

思路3

以上冒泡过程其实只需要最小元素,那么可以用小顶堆来代替。
那也就是O(nlogk)

如果直接把所有元素放进小顶堆,再统一取出,也是O(nlogk)

但是空间复杂度上,前者O(k),后者O(n)

代码实现

public ListNode mergeKLists(ListNode[] lists){
        PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });
        for (int i = 0; i < lists.length; i++) {
            if (lists[i]!=null) queue.offer(lists[i]);
        }
        ListNode newHead = new ListNode(-1);
        ListNode node = newHead;
        while (!queue.isEmpty()){
            ListNode cur = queue.poll();
            node.next = cur;
            node = node.next;
            if (cur.next!=null) queue.offer(cur.next);
        }
        return newHead.next;
    }

leetcode结果:

5ms 
41.6MB

分治(来自leetcode题解)

class Solution {
   public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) return null;
        return merge(lists, 0, lists.length - 1);
    }

    private ListNode merge(ListNode[] lists, int left, int right) {
        if (left == right) return lists[left];
        int mid = left + (right - left) / 2;
        ListNode l1 = merge(lists, left, mid);
        ListNode l2 = merge(lists, mid + 1, right);
        return mergeTwoLists(l1, l2);
    }

    private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1,l2.next);
            return l2;
        }
    }
}

作者:powcai
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/leetcode-23-he-bing-kge-pai-xu-lian-biao-by-powcai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

或许可以使用ForkJoinPool?(存疑)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值