Leetcode1-100: 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

题目要求是合并k个已经排序后的字符串。

解题思路

  1. 类似于brute force 吧,不过过程中还是需要一些操作来减少时间复杂度的。通过一个mask变量来看是否跳出循环,只有在只剩下一个非空子串的时候选择跳出循环。
  2. Priority Queue,使用优先队列来帮助实现入栈和出栈来减少时间复杂度。因为优先队列的出栈时间复杂度是O(log(k)),就不需要用线性时间来比较所有队首元素的大小了
  3. Divide and conquer,每次合并两个元素然后到下一级知道合并成一个元素
    在这里插入图片描述

代码实现

implement 1 Brute force

    public ListNode mergeKLists(ListNode[] lists) {
        if(lists.length == 0) return null;
        ListNode dummy = new ListNode(-1), p = dummy;
        while(true) {
            int mask = 0, min = Integer.MAX_VALUE;
            int candidate = -1;
            for(int i = 0; i < lists.length; i++) {
                if(lists[i] == null) mask++; //统计空串的数量
                else {
                    if(lists[i].val < min) {
                        min = lists[i].val;
                        candidate = i;
                    }
                }
            }
            if(mask == lists.length - 1) { //当前得到的最小值是最后一个值串
                p.next = lists[candidate];
                return dummy.next;
            }
            else if(mask == lists.length) {
                return null;
            }
            else {
                p.next = lists[candidate];
                lists[candidate] = lists[candidate].next;
                p = p.next;
            }
        }
    }

在这里插入图片描述
复杂度分析:

时间复杂度:假设最长的链表长度是 n ,那么 while 循环将循环 n 次。
假设链表列表里有 k 个链表,for 循环执行 k 次,所以时间复杂度是 O(kn)

空间复杂度:O(1)(没有创建节点,直接改变链表的指向)

implement 2 Priority Queue

    public ListNode mergeKLists(ListNode[] lists) { 
        Comparator<ListNode> cmp;
        cmp = new Comparator<ListNode>() {  
       // 需要先定义比较器来帮助队列判断ListNode的大小关系
        @Override
        public int compare(ListNode o1, ListNode o2) {
            // TODO Auto-generated method stub
            return o1.val-o2.val;
        }
        };
 
        Queue<ListNode> q = new PriorityQueue<ListNode>(cmp);
        for(ListNode l : lists){
            if(l!=null){
                q.add(l);
            }        
        }
        ListNode head = new ListNode(0);
        ListNode point = head;
        while(!q.isEmpty()){ 
        	//出队列一个元素
            point.next = q.poll();
            point = point.next; 
            ListNode next = point.next;
            将新元素加进队列
            if(next!=null){
                q.add(next);
            }
        }
        return head.next;
    }

在这里插入图片描述
复杂度分析:

时间复杂度:假如总共有 N 个节点,每个节点入队出队都需要 log(k),
所有时间复杂度是 O(N log(k))

空间复杂度:优先队列需要 O(k)的复杂度

implement 3. Divide and conquer

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode h = new ListNode(0);
    ListNode ans=h;
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            h.next = l1;
            h = h.next;
            l1 = l1.next;
        } else {
            h.next = l2;
            h = h.next;
            l2 = l2.next;
        }
    }
    if(l1==null){
        h.next=l2;
    }
    if(l2==null){
        h.next=l1;
    } 
    return ans.next;
}
public ListNode mergeKLists(ListNode[] lists) {
    if(lists.length==0){
        return null;
    }
    int interval = 1;
    while(interval<lists.length){
        System.out.println(lists.length);
        for (int i = 0; i + interval< lists.length; i=i+interval*2) {
            lists[i]=mergeTwoLists(lists[i],lists[i+interval]);            
        }
        interval*=2;
    }

    return lists[0];
}

在这里插入图片描述
复杂度分析:

时间复杂度:假设每个链表的长度都是 n ,有 k 个链表,记总结点数是 N = n * k.
那么时间复杂度就是O(Nlogk)
空间复杂度:O(1)

分析

这题的方法有很多,甚至leetcode的solution给出第一个brute force是把所有元素直接放到一个数组里面然后再排序。
后面两种实现就没有自己写,参考了一下评论里面大佬们的解法粘上去了,大家有兴趣的可以去看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值