leetcode-23. Merge k Sorted Lists

126 篇文章 0 订阅
44 篇文章 0 订阅

leetcode-23. Merge k Sorted Lists

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

leetcode-21. Merge Two Sorted Lists

常规思路n*k

第一次做这个的时候没有限制时间复杂度,写出来像下面这样的代码。这个的复杂度应该是n*k。n是节点数,k是多少个链表数。然后提交的时候TLE。。。。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode[] ds = new ListNode[lists.length];
        for(int i = 0 ; i < lists.length; i++){
            ds[i] = new ListNode(0);
            ds[i].next = lists[i];
        }
        ListNode dump = new ListNode(0);
        ListNode ret = dump;
        int c = 0;
        for(ListNode n : ds){
            while(n.next !=null){
                n = n.next;
                c++;
            }
        }
        while(c--!=0){
            int p = 0,v=Integer.MAX_VALUE;
            for(int i = 0 ; i < ds.length ; i++){
                if(ds[i].next!= null && v > ds[i].next.val){
                    v = ds[i].next.val;
                    p = i;
                }
            }
            dump.next = ds[p].next;
            dump = dump.next;
            ds[p].next = ds[p].next.next;
        }
        return ret.next;
    }
}

n*logk的mergesort解法

不过也是显然的。。
想要优化的这里时间上基本的思路还是从SortList上面入手,基本上向这样多个链表的题用分治二分之类的算法都会把时间复杂度从n降到logn的水平。是一种比较常见的简化思路。加上之前做过的21题,实际上也算是有了提示。这里只要不断二分问题然后将其转换成为2个节点2个节点之间的merge就可以以logn的复杂度来做。
所以这里的时间复杂度是n*logk;

/**
 * Definition for singly-linked list.
 * 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;
        return helper(lists,0,lists.length-1);
    }

    private ListNode helper(ListNode[] lists, int start, int end){
        if(start==end){
            return lists[start];
        }else if(start < end){
            int mid = (end - start) / 2 + start;
            ListNode left = helper(lists, start, mid);
            ListNode right = helper(lists, mid + 1, end);
            return mergeTwoLists(left, right);
        }else{
            return null;
        }
    }

    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null) return l2;
        if(l2==null) return l1;
        ListNode d1 = new ListNode(0);
        ListNode d2 = new ListNode(0);
        ListNode ret = new ListNode(0);
        ListNode tmp = ret;
        d1.next = l1;
        d2.next = l2;
        while(d1.next != null && d2.next != null){
            if(d1.next.val < d2.next.val){
                tmp.next = d1.next;
                d1.next = d1.next.next;
            }else{
                tmp.next = d2.next;
                d2.next = d2.next.next;
            }
            tmp = tmp.next;
        }
        if(d2.next != null) d1.next =d2.next;
        tmp.next = d1.next;
        return ret.next;
    }
}

AC的堆解法

另外,其实这题也可以用堆来做。。但是这样写法好像比较鸡贼,,但是确实也是一种有效的解法。而且简洁的多。。这个的复杂度实际上是nlogn。但是这个只是AC的解法。并不是说最好的,正确的堆的用法在下一小节说。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<Integer> deap = new PriorityQueue<Integer>();
        for(ListNode n : lists){
            while(n !=null){
                deap.add(n.val);
                n=n.next;
            }
        }
        ListNode dump = new ListNode(0);
        ListNode ret = dump;
        while(!deap.isEmpty()){
            dump.next = new ListNode(deap.poll());
            dump = dump.next;
        }
        return ret.next;
    }
}

n*logk的堆解法

正确的堆的解法应该是先将每个链表的头结点放入堆中,然后一个一个的poll出来,然后在将每个链表的头节点放入堆中,如此往复,这样的话时间复杂度也是n*logk。也是一种很有意思的方法。

这个解法我没有做了。下面的实现是讨论里的,他是重写写了一个比较器。这个实现上更优雅一些。。比我之前想的更好一些。
解法来源

public class Solution {
    public ListNode mergeKLists(List<ListNode> lists) {
        if (lists==null||lists.size()==0) return null;

        PriorityQueue<ListNode> queue= new PriorityQueue<ListNode>(lists.size(),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 0;
                else 
                    return 1;
            }
        });

        ListNode dummy = new ListNode(0);
        ListNode tail=dummy;

        for (ListNode node:lists)
            if (node!=null)
                queue.add(node);

        while (!queue.isEmpty()){
            tail.next=queue.poll();
            tail=tail.next;

            if (tail.next!=null)
                queue.add(tail.next);
        }
        return dummy.next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值