• 23. Merge k Sorted Lists


    • 解法一

      因为前面已经有Merge Two Sorted Lists这道题目的铺垫,所以第一个想法是合并k个链表,那就两两合并,所以解法一的思路比较简单。

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     ListNode *next;
       *     ListNode(int x) : val(x), next(NULL) {}
       * };
       */
      class Solution 
      {
      public:
          ListNode* mergeKLists(vector<ListNode*>& lists)
      	{
              int k = lists.size();  //一共有多少个链表
      		ListNode* newhead = NULL;
      		int i = 0;
      		while(i < k)
      		{
      			ListNode* head1 = lists[i];
      			newhead = mergeTwoLists(head1,newhead);
      			i++;
      		}
      		
      		return newhead;
          }
      private:
          /*每次合并两个链表*/
      	ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
      	{
      		ListNode* headnode = new ListNode(0);
      		headnode->next = NULL;
      		ListNode* pre = headnode;  //尾指针初始状态下指向头节点
      		
      		//注意题目中l1和l2都没有头节点
      		while(l1 != NULL && l2 != NULL)
      		{
      			if(l1->val > l2->val)
      			{
      				pre->next = l2;
      				pre = pre->next;
      				l2 = l2->next;
      			}
      			else
      			{
      				//相等 或 l1 比 l2小 都应该执行这里
      				pre->next = l1;
      				pre = pre->next;
      				l1 = l1->next;
      			}
      			
      		}
      		
      		if(l1)
      		{
      			pre->next = l1;
      			l1 = NULL;
      		}
      		
      		if(l2)
      		{
      			pre->next = l2;
      			l2= NULL;
      		}
      		
      		return headnode->next;
      	}
      };
    
    • 解法二 使用最小堆
      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     ListNode *next;
       *     ListNode(int x) : val(x), next(NULL) {}
       * };
       */
      class Solution 
      {
      public:
          ListNode* mergeKLists(vector<ListNode*>& lists)
      	{
      		ListNode dummy(0);
      		ListNode* tail = &dummy;
              
      		auto comp = [](ListNode* a,ListNode* b){return a->val > b->val;};
      		priority_queue<ListNode*,vector<ListNode*>,decltype(comp)> dataqueue(comp);
      		//ListNode* head;
      		
      		for(ListNode* list : lists)
      		{
      			if(list)
      			{
      				dataqueue.push(list);
      			}
      		}
      		
      		while(!dataqueue.empty())
      		{
      			tail->next = dataqueue.top();
      			dataqueue.pop();
      			tail = tail->next;
      			
      			if(tail->next)
      			{
      				dataqueue.push(tail->next);
      			}
      		}
      		return dummy.next;
          }
      };
    

    首先建立一个最小堆,将l1 l2 l3头部的三个元素依次插入到最小堆中,此时最小堆内的元素为{1,1,2},将最小堆的堆顶1弹出,链接到tail后面,同时由于这个1来自l1,则将l1中的下一个元素4插入最小堆,此时最小堆内的元素为{1,2,4},再弹出最小堆的堆顶,链接到tail后面,同时由于这个1来自链表l2,因此将l2中的下一个元素插入到最小堆中,此时最小堆内元素为{2,3,4},重复这个过程,直到最小堆内的元素为空。

    假设有k个链表,每个链表的长度为n,则时间复杂度为:O(kn * log k) 空间复杂度为O(k) + O(n)

    • 解法三 分治思想
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
     /*分治思想解决*/
    class Solution 
    {
    public:
        ListNode* mergeKLists(vector<ListNode*>& lists)
    	{
    		int r = 0;
    		int l = lists.size();
            return merge(lists,r,l - 1);
        }
    private:
        ListNode* merge(vector<ListNode*>& lists,int r,int l)
    	{
    		int center = 0;
    		if(r > l)
    		{
    			return NULL;
    		}
    		if(r == l)
    		{
    			return lists[r];
    		}
    		
    		if(r + 1 == l)
    		{
    			return mergeTwoLists(lists[r],lists[l]);
    		}
    		
    		ListNode* left = NULL;
    		ListNode* right = NULL;
    		center = (r + l) / 2;
    		left = merge(lists,r,center);  //递归解决左边
    		right = merge(lists,center + 1,l);  //递归解决右边
    		
    		return mergeTwoLists(left,right);
    		
    	}
        /*合并两个链表*/
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
    	{
    		ListNode* headnode = new ListNode(0);
    		headnode->next = NULL;
    		ListNode* pre = headnode;  //尾指针初始状态下指向头节点
    		
    		//注意题目中l1和l2都没有头节点
    		while(l1 != NULL && l2 != NULL)
    		{
    			if(l1->val > l2->val)
    			{
    				pre->next = l2;
    				pre = pre->next;
    				l2 = l2->next;
    			}
    			else
    			{
    				//相等 或 l1 比 l2小 都应该执行这里
    				pre->next = l1;
    				pre = pre->next;
    				l1 = l1->next;
    			}
    			
    		}
    		
    		if(l1)
    		{
    			pre->next = l1;
    			l1 = NULL;
    		}
    		
    		if(l2)
    		{
    			pre->next = l2;
    			l2= NULL;
    		}
    		
    		return headnode->next;
    	}
    };
    

    分治思想是如果想解决lists中链表合并,就先解决左半部分的链表合并,得到合并后的链表left,再解决右半部分的链表合并,得到合并后的链表right,然后再将左半部分和右半部分分别合并起来即可。而想要得到left,就需要重复上面的过程。

  • 相关阅读:
    UT斯达康 G680手机那些事儿
    VoIP使用总结
    Test
    Remove "Click here to enable Instant Search"
    常用的在线播放(电台和电视台)
    Sipdroid Error “Registration failed (404 not found)”
    通过Word 2007发布Blog
    【Go反射】读取对象
    【Go反射】修改对象
    【爬虫】callback=jQuery+数字在爬虫中如何模拟
  • 原文地址:https://www.cnblogs.com/Manual-Linux/p/12118207.html
Copyright © 2020-2023  润新知