• Leetcode23:Merge k Sorted Lists


    Leetcode23:Merge k Sorted Lists

    1. 题目描述

    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
    把K个已经排序的链表合并到一起并返回它的链表头,分析并描述它的复杂度。

    2. 解题思路

    这道题的难度是hard。这道题的解题思路有三种:

    1. 首先合并前两个链表得到一个链表,然后再和第三个合并,然后再和第四个合并,依次合并下去,直到最后得到一个链表。我们计算一下复杂度。

    1、2合并,遍历2n个节点
    1,2结果和3合并,遍历3n个节点
    1,2,3结果和4合并,遍历4n个节点
    1,2,3,..,k-1结果和k合并,遍历kn个节点
    总共遍历的节点数目为n(2+3+…+k) = n*(k^2+k-2)/2, 因此时间复杂度是O(n*(k^2+k-2)/2) = O(nk^2)。

    1. 利用分治的思想,先把m个链表的合并分成m/2个双链表的合并,然后一次递减直到只有最后的一个或者两个链表。仔细想想这个过程是不是二分的逆过程。这个可以使用递归来实现,同样的思路在合并两个链表里也使用过。因此算法复杂度为T(k) = 2T(k/2) + O(nk),推导得到算法复杂度为O(nklogk)。

    1、3合并,合并结果放到1的位置
    2、4合并,合并结果放到2的位置
    再把1、2合并(相当于原来的13 和 24合并)

    1. 维护一个k个大小的最小堆,初始化堆中元素为每个链表的头结点,每次从堆中选择最小的元素加入到结果链表,再选择该最小元素所在链表的下一个节点加入到堆中。这样当堆为空时,所有链表的节点都已经加入了结果链表。元素加入堆中的复杂度为O(longk),总共有kn个元素加入堆中,因此,复杂度也和算法2一样是O(nklogk)。

    3.代码实现

    1. 依次合并
    class Solution {
     public ListNode mergeKLists(ListNode[] lists) {
    	 int n = lists.length;
    	
    	 if(n==0 || lists==null)
    		 return null;
         //if(n==1)
           //  return lists[0];       
    		 for(int i=1;i<n;i++) {
    			 lists[0] = mergeTwoLists(lists[0],lists[i]);
    		 }
    		 n = k;
    	 }
    	 return lists[0];
     }
         public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
            if(l1==null)
                return l2;
            if(l2==null)
            	return l1;
            ListNode head = null;
           
            ListNode head_c = l1.val>l2.val?l2:l1;
            head = head_c;
            
            while(l1 !=null && l2!=null) {
            	if(l1.val>l2.val) {
            		head.next = l2;
            		l2 = l2.next;
            	}
            	else {
            		head.next = l1;
            		l1 = l1.next;
            	}
            }
            if(l1==null) {
            	head.next = l2;
            }
            else {
            	head.next = l1;
            }
            return head_c.next;
        }
    }
    
    1. 分支思想、两两合并
    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
     public ListNode mergeKLists(ListNode[] lists) {
    	 int n = lists.length;
    	
    	 if(n==0 || lists==null)
    		 return null;
         //if(n==1)
           //  return lists[0];
    	 while(n>1) {
    		 int k = (n+1)/2;
             
    		 for(int i=0;i<n/2;i++) {//注意这里i的取值范围,因为n存在奇偶两种情况
    			 lists[i] = mergeTwoLists1(lists[i],lists[i+k]);
    		 }
    		 n = k;
    	 }
    	 return lists[0];
     }
      public ListNode mergeTwoLists1(ListNode l1, ListNode l2) {
            if(l1==null)
                return l2;
            if(l2==null)
            	return l1;
           if(l1.val<l2.val) {
        	   l1.next = mergeTwoLists1(l1.next,l2);
        	   return l1;
           }else {
        	   l2.next = mergeTwoLists1(l2.next,l1);
        	   return l2;  
           }
        }
    }
    
    1. 维护最小堆
    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;
                }
            });//建堆并重写compare函数
            
            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;
        }
    }
    
    
  • 相关阅读:
    《生命摆渡人》 读书笔记 读后感
    《饮食术》 读书笔记 读后感
    《天生有罪》读后感 读书笔记
    《内在动机》 读后感 读书笔记
    《从疾病到人心》读后感 读书笔记
    Python 入门书籍文档推荐及学习笔记总结
    JavaScript 入门书籍推荐及学习笔记总结 -- 《JavaScript权威指南》
    JavaScript中window.onload事件与document.ready事件的区别
    CentOS 7 中安装 MySQL 8 以及 MySQL 常用操作
    Python 杂记:argparse 模块
  • 原文地址:https://www.cnblogs.com/chailinbo/p/7586689.html
Copyright © 2020-2023  润新知