1. 程式人生 > >[LeetCode] Merge k Sorted Lists 合併k個有序連結串列

[LeetCode] Merge k Sorted Lists 合併k個有序連結串列

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

這道題讓我們合併k個有序連結串列,之前我們做過一道Merge Two Sorted Lists 混合插入有序連結串列,是混合插入兩個有序連結串列。這道題增加了難度,變成合並k個有序連結串列了,但是不管合併幾個,基本還是要兩兩合併。那麼我們首先考慮的方法是能不能利用之前那道題的解法來解答此題。答案是肯定的,但是需要修改,怎麼修改呢,最先想到的就是兩兩合併,就是前兩個先合併,合併好了再跟第三個,然後第四個直到第k個。這樣的思路是對的,但是效率不高,沒法通過OJ,所以我們只能換一種思路,這裡就需要用到分治法 Divide and Conquer Approach。簡單來說就是不停的對半劃分,比如k個連結串列先劃分為合併兩個k/2個連結串列的任務,再不停的往下劃分,直到劃分成只有一個或兩個連結串列的任務,開始合併。舉個例子來說比如合併6個連結串列,那麼按照分治法,我們首先分別合併1和4,2和5,3和6。這樣下一次只需合併3個連結串列,我們再合併1和3,最後和2合併就可以了。參見程式碼如下:

解法一:

class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        if (lists.size() == 0) return NULL;
        int n = lists.size();
        while (n > 1) {
            int k = (n + 1) / 2;
            for (int i = 0; i < n / 2; ++i) {
                lists[i] 
= mergeTwoLists(lists[i], lists[i + k]); } n = k; } return lists[0]; } ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { ListNode *head = new ListNode(-1); ListNode *cur = head; while (l1 && l2) {
if (l1->val < l2->val) { cur->next = l1; l1 = l1->next; } else { cur->next = l2; l2 = l2->next; } cur = cur->next; } if (l1) cur->next = l1; if (l2) cur->next = l2; return head->next; } };

我們再來看另一種解法,這種解法利用了最小堆這種資料結構,我們首先把k個連結串列的首元素都加入最小堆中,它們會自動排好序。然後我們每次取出最小的那個元素加入我們最終結果的連結串列中,然後把取出元素的下一個元素再加入堆中,下次仍從堆中取出最小的元素做相同的操作,以此類推,直到堆中沒有元素了,此時k個連結串列也合併為了一個連結串列,返回首節點即可,程式碼如下:

解法二:

struct cmp {
    bool operator () (ListNode *a, ListNode *b) {
        return a->val > b->val;
    }
};
 
class Solution {  
public:  
    ListNode *mergeKLists(vector<ListNode *> &lists) {  
        priority_queue<ListNode*, vector<ListNode*>, cmp> q;
        for (int i = 0; i < lists.size(); ++i) {
            if (lists[i]) q.push(lists[i]);
        }
        ListNode *head = NULL, *pre = NULL, *tmp = NULL;
        while (!q.empty()) {
            tmp = q.top();
            q.pop();
            if (!pre) head = tmp;
            else pre->next = tmp;
            pre = tmp;
            if (tmp->next) q.push(tmp->next);
        }
        return head;
    }  
};  

參考資料: