leetcode 23. Merge k Sorted Lists(堆||分治法)


Merge k sorted linked lists and return it as one sorted list. 

題意:把k個已經排好序的鏈表整合到一個鏈表中,並且這個鏈表是排了序的。

題解:這是一道經典好題,值得仔細一說。

有兩種方法,假設每個鏈表的平均長度是n,那么這兩種方法的時間復雜度都是O(nklogk)。

方法一

基本思路是:把k個鏈表開頭的值排個序,每次取最小的一個值放到答案鏈表中,這次取完之后更新這個值為它后面的一個值。接着這么取一直到全部取完。那么每次更新之后怎么對當前這k個值重新排序以便知道當前最小的是誰呢?用優先隊列(或者堆)來維護這k個值就好啦!

由於每個值都要取一次,一共取nk次。每次更新優先隊列要logk的復雜度。所以總時間復雜度為O(nklogk);空間復雜度為優先隊列所占空間,為O(k)。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution
{
public:
    struct cmp
    {
        bool operator() (const ListNode* a,const ListNode* b)
        {
            return a->val  > b->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists)
    {
        priority_queue<ListNode*, vector<ListNode*>, cmp>pq;
        for(auto i:lists)
        {
            if(i) //這句判斷很有必要,不能把空的加入隊列。比如這組數據:[[],[]]
            {
                pq.push(i);
            }
        }
        if(pq.empty())
        {
            return nullptr;
        }
        ListNode* ans = pq.top();
        pq.pop();
        ListNode* tail = ans;
        if(tail->next)
        {
            pq.push(tail->next);
        }
        while(!pq.empty())
        {
            tail->next = pq.top();
            tail = tail->next;
            pq.pop();
            if(tail->next)
            {
                pq.push(tail->next);
            }
        }
        return ans;
    }
};

方法二:

和方法一的思路不同:考慮分治的思想來解這個題(類似歸並排序的思路)。把這些鏈表分成兩半,如果每一半都合並好了,那么我就最后把這兩個合並了就行了。這就是分治法的核心思想。

但是這道題由於存的都是指針,就具有了更大的操作靈活性,可以不用遞歸來實現分治。就是先兩兩合並后在兩兩合並。。。一直下去直到最后成了一個。(相當於分治算法的那棵二叉樹從底向上走了)。

第一次兩兩合並是進行了k/2次,每次處理2n個值。

第二次兩兩合並是進行了k/4次,每次處理4n個值。

。。。

最后一次兩兩合並是進行了k/(2^logk)次,每次處理2^logK*N個值。

所以時間復雜度:

O((2N) * (K / 2) + (4N) * (K / 4) + (8N) * (K / 8) + .............. + (2^logK*N) * (K / (2 ^logK)) )=O( logK*KN)

空間復雜度是O(1)。

/**
 * 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) {
    if(lists.empty()){
        return nullptr;
    }
    while(lists.size() > 1){
        lists.push_back(mergeTwoLists(lists[0], lists[1]));
        lists.erase(lists.begin());
        lists.erase(lists.begin());
    }
    return lists.front();
    }
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
        if(l1 == nullptr){
            return l2;
        }
        if(l2 == nullptr){
            return l1;
        }
        if(l1->val <= l2->val){
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else{
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM