Merge k Sorted Lists 归并k个链表

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

假设大家已经熟悉2个链表如何归并了。

在这里我讲介绍2种方法归并k个链表,这两种方法的复杂度都是O(nlogk) (n 为所有节点的个数)

第一种是基于分治思想的递归法。第二种是基于PriorityQueue的。

先来看第一种:基于分治的思想。

对于k个链表,把它们分成左一半,右一半。

假设左一半已经归并好了 left = merge(0, mid ),右一半也归并好了right = merge(mid + 1, k)。

那么现在需要做的就是再把 left 和 right 做2个链表归并的操作。

那么左一半如何具体进行归并呢? 可以再把它一切为2, 归并下去。

递归的停止条件就是,需要归并的链表数 <=2个。

这种方法的空间复杂度为O(1)。

代码写起来也很简洁,显示了递归的优美。

运行时间:


代码:

    public ListNode mergeKLists(ListNode[] lists) {
        return doMergeList(lists, 0, lists.length - 1);
    }

    public ListNode doMergeList(ListNode[] lists, int begin, int end) {
        if (end < begin) {
            return null;
        }
        if (end == begin) {
            return lists[begin];
        } else if (end - begin == 1) {
            //do Merge two list
            return mergeTwoLists(lists[begin], lists[end]);
        } else {
            int mid = (begin + end) / 2;
            return mergeTwoLists(doMergeList(lists, begin, mid), doMergeList(lists, mid + 1, end));
        }
    }

    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode fakeNode = new ListNode(-1), cur = fakeNode, curl1 = l1, curl2 = l2;
        while (curl1 != null && curl2 != null) {
            if (curl1.val < curl2.val) {
                cur.next = curl1;
                curl1 = curl1.next;
            } else {
                cur.next = curl2;
                curl2 = curl2.next;
            }
            cur = cur.next;
        }
        cur.next = curl1 != null ? curl1 : curl2;
        return fakeNode.next;
    }
接下来看基于PriorityQueue的
首先我们先明白一下什么是PriorityQueue。

它是一种特殊的queue,不同于先进先出,它里面的顺序是按照优先级排列的。

比如我有一个数组[1, 5, 6, 2, - 1]

如果把它放到PriorityQueue中去,那么在PriorityQueue中的排列就会变成[ - 1, 1, 2, 5, 6 ]

如果poll () 的话,会返回-1。

放进PriorityQueue中的变量,必须要是可以比较的。

我们想把ListNode的变量放进去。 (java的话,需要传给PriorityQueue的一个 ListNode 的 comparator )

具体的操作过程为:

假设我的lists值分别为:

node0 : 1 - > 2 -> 3

node1 : - 4 -> 4 -> 5

node2 : 0 -> 2

我将这3个node放到queue中。

此时queue长这样:

node1 : - 4 -> 4 -> 5

node2 : 0 -> 2

node0 : 1 - > 2 -> 3

所以,pop的时候,会弹出node1 :  - 4 -> 4 -> 5

此时:cur :- 4

node1.next != null, 将 4 - > 5 再放入queue

此时queue长这样:

0 -> 2

1 - > 2 -> 3

4 -> 5

继续进行pop,弹出 0 - >2

此时:cur:  -4 - > 0

将 2再放入queue。

...

直至queue为null,

此时,所有的都排好序了。

空间复杂度 O ( k )

运行时间:



代码:

  public ListNode mergeByPriorityQueue(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                if (o1.val < o2.val) {
                    return -1;
                }
                else if (o1.val > o2.val) {
                    return 1;
                }
                return 0;
            }
        });
        for (ListNode node : lists) {
            if (node != null) {
                queue.add(node);
            }
        }
        ListNode fakeHead = new ListNode(-1), cur = fakeHead;
        while (!queue.isEmpty()) {
            ListNode node = queue.poll();
            cur.next = node;
            cur = cur.next;
            if (node.next != null) {
                queue.add(node.next);
            }
        }
        return fakeHead.next;
    }
参考资料:

https://leetcode.com/discuss/9279/a-java-solution-based-on-priority-queue

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值