23. 合并K个排序链表(C++)

题目描述:

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

 

参考:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/he-bing-kge-pai-xu-lian-biao-by-leetcode-solutio-2/

思想1:顺序合并

最朴素的方法:用一个变量 ans 来维护以及合并的链表,第 i 次循环把第 i个链表和 ans 合并,答案保存到 ans 中。

代码1:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* merge2Lists(ListNode* l1,ListNode* l2){
        if(!l1 || !l2)
            return l1?l1:l2;
        ListNode *p,head;
        p = &head;
        while(l1 && l2){
            if(l1->val > l2->val){
                p->next = l2;
                l2 = l2->next;
            }
            else {
                p->next = l1;
                l1 = l1->next;
            }
            p = p->next;
        }
        if(l1 != NULL)
            p->next = l1;
        else   
            p->next = l2;
        return head.next;
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode* p = nullptr;
        for(int i=0;i<lists.size();i++)
            p = merge2Lists(p,lists[i]);
        return p;
    }
};

复杂度:

时间复杂度:假设每个链表的最长长度是 n。在第一次合并后,ans 的长度为 n;第二次合并后,ans 的长度为 2xn,第 i次合并后,ans 的长度为 ixn。第 i 次合并的时间代价是 O(n+(i−1)×n)=O(i×n),那么总的时间代价为,故渐进时间复杂度为 O(k^2 n)。
空间复杂度:没有用到与 k 和 n 规模相关的辅助空间,故渐进空间复杂度为O(1)。

 

思想2:分治合并

将 k 个链表配对并将同一对中的链表合并;
第一轮合并以后, k 个链表被合并成了k/2个链表,平均长度为 2n/k,然后是 k/4个链表,k/8个链表等等;
重复这一过程,直到得到了最终的有序链表。

代码2:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* merge2Lists(ListNode* l1,ListNode* l2){
        if(!l1 || !l2)
            return l1?l1:l2;
        ListNode *p,head;
        p = &head;
        while(l1 && l2){
            if(l1->val > l2->val){
                p->next = l2;
                l2 = l2->next;
            }
            else {
                p->next = l1;
                l1 = l1->next;
            }
            p = p->next;
        }
        p->next = l1?l1:l2;
        return head.next;
    }
    ListNode* merge(vector<ListNode*>& lists,int left,int right){
        if(left == right)
            return lists[left];
        if(left > right)
            return nullptr;
        int mid = (left + right) >> 1;
        return merge2Lists(merge(lists,left,mid),merge(lists,mid+1,right));
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return merge(lists,0,lists.size()-1);
    }
};

复杂度:

时间复杂度:考虑递归「向上回升」的过程——第一轮合并k/2组链表,每一组的时间代价是 O(2n);第二轮合并 k/4组链表,每一组的时间代价是 O(4n)......所以总的时间代价是 O(kn×logk),故渐进时间复杂度为 O(kn×logk)。
空间复杂度:递归会使用到O(logk) 空间代价的栈空间。

思想3:使用优先队列

后续添加

posted @ 2020-05-15 13:47  thefatcat  阅读(463)  评论(0编辑  收藏  举报