LeetCode:Merge k Sorted Lists


題目鏈接

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

合並k個有序的鏈表,我們假設每個鏈表的平均長度是n。這一題需要用到合並兩個有序的鏈表子過程

 

算法1

最傻的做法就是先1、2合並,12結果和3合並,123結果和4合並,…,123..k-1結果和k合並,我們計算一下復雜度。

1、2合並,遍歷2n個節點

12結果和3合並,遍歷3n個節點

123結果和4合並,遍歷4n個節點

123..k-1結果和k合並,遍歷kn個節點

總共遍歷的節點數目為n(2+3+…+k) = n*(k^2+k-2)/2, 因此時間復雜度是O(n*(k^2+k-2)/2) = O(nk^2),代碼如下:

/**
 * 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.size() == 0)return NULL;
        ListNode*res = lists[0];
        for(int i = 1; i < lists.size(); i++)
            res = merge2list(res, lists[i]);
        return res;
    }
    
    ListNode *merge2list(ListNode *head1, ListNode*head2)
    {
        ListNode node(0), *res = &node;
        while(head1 && head2)
        {
            if(head1->val <= head2->val)
            {
                res->next = head1;
                head1 = head1->next;
            }
            else
            {
                res->next = head2;
                head2 = head2->next;
            }
            res = res->next;
        }
       if(head1)
            res->next = head1;
        else if(head2)
            res->next = head2;
        return node.next;
    }
};

算法2:利用分治的思想把合並k個鏈表分成兩個合並k/2個鏈表的任務,一直划分,知道任務中只剩一個鏈表或者兩個鏈表。可以很簡單的用遞歸來實現。因此算法復雜度為T(k) = 2T(k/2) + O(nk),很簡單可以推導得到算法復雜度為O(nklogk)

遞歸的代碼就不貼了。下面是非遞歸的代碼非遞歸的思想是(以四個鏈表為例):                   本文地址

1、3合並,合並結果放到1的位置

2、4合並,合並結果放到2的位置

再把1、2合並(相當於原來的13 和 24合並)

/**
 * 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 n = lists.size();
        if(n == 0)return NULL;
        while(n >1)
        {
            int k = (n+1)/2;
            for(int i = 0; i < n/2; i++)
                lists[i] = merge2list(lists[i], lists[i + k]);
            n = k;
        }
        return lists[0];
    }
    
    ListNode *merge2list(ListNode *head1, ListNode*head2)
    {
        ListNode node(0), *res = &node;
        while(head1 && head2)
        {
            if(head1->val <= head2->val)
            {
                res->next = head1;
                head1 = head1->next;
            }
            else
            {
                res->next = head2;
                head2 = head2->next;
            }
            res = res->next;
        }
        if(head1)
            res->next = head1;
        else if(head2)
            res->next = head2;
        return node.next;
    }
};

 


算法3:維護一個k個大小的最小堆,初始化堆中元素為每個鏈表的頭結點,每次從堆中選擇最小的元素加入到結果鏈表,再選擇該最小元素所在鏈表的下一個節點加入到堆中。這樣當堆為空時,所有鏈表的節點都已經加入了結果鏈表。元素加入堆中的復雜度為O(longk),總共有kn個元素加入堆中,因此,復雜度也和算法2一樣是O(nklogk)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 * int val;
 * ListNode *next;
 * ListNode(int x) : val(x), next(NULL) {}
 * };
 */

class Solution {
private:
struct cmp
{
    bool operator ()(const ListNode *a, const ListNode *b)
    {
            return a->val > b->val;
    }
};
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        int n = lists.size();
        if(n == 0)return NULL;
        ListNode node(0), *res = &node;
        priority_queue<ListNode*, vector<ListNode*>, cmp> que;
        for(int i = 0; i < n; i++)
            if(lists[i])
                que.push(lists[i]);
        while(!que.empty())
        {
            ListNode * p = que.top();
            que.pop();
            res->next = p;
            res = p;
            
            if(p->next)
                que.push(p->next);
        }
        return node.next;
    }
};

【版權聲明】轉載請注明出處http://www.cnblogs.com/TenosDoIt/p/3673188.html


免責聲明!

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



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