【LeetCode】23. 合并K个排序链表

题目

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

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

思路一:顺序合并

基于合并两个链表,取第一个链表与第二个链表合并,然后将合并的链表再与第三个链表合并,依次类型。

代码

时间复杂度:假设每个链表的最长长度是 n,渐进时间复杂度为 O(k^2 * n)
空间复杂度:没有用到与 k 和 n 规模相关的辅助空间,故渐进空间复杂度为 O(1)。

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.empty()) return nullptr;
        int n = lists.size();
        ListNode *res = lists[0];
        for (int i = 1; i < n; ++i) {
            res = mergeTwoLists(res, lists[i]);
        }
        return res;
    }
    ListNode* merge2(ListNode *l1, ListNode *l2) {
        ListNode *root = new ListNode(0), *pre = root;        
        while (l1 && l2) {
            if (l1->val <= l2->val) {
                pre->next = l1;
                l1 = l1->next;
            } else {
                pre->next = l2;              
                l2 = l2->next;
            }
            pre = pre->next;
        }
        pre->next = l1 ? l1 : l2;        
        return root->next;
    }
};

思路二:分治合并放入队列

基于merge思想,将k个链表放入队列,取出两个进行合并,合并后在放入队尾,直到只有队列中只有一个元素。
注意:vector转队列需要先转双端队列。

代码

击败99.05%
时间复杂度:考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn * logk)。
空间复杂度:这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        int size = lists.size();
        if (size == 0) {
            return nullptr;
        }
        if (size == 1) {
            return lists[0];
        }
        queue<ListNode*> waiting(deque<ListNode*>(lists.begin(), lists.end())); //将vector转为队列
        //如果队列元素大于1,则取出两个进行合并,合并后的链表继续添加到链表尾部
        while (waiting.size() > 1) {
            ListNode *l1 = waiting.front();
            waiting.pop();
            ListNode *l2 = waiting.front();
            waiting.pop();
            ListNode *p = merge2(l1, l2);//可以取消生成变量
            waiting.push(p);
        } 
        return waiting.front();
    }
    ListNode* merge2(ListNode *l1, ListNode *l2) {
        ListNode *root = new ListNode(0), *pre = root;        
        while (l1 && l2) {
            if (l1->val <= l2->val) {
                pre->next = l1;
                l1 = l1->next;
            } else {
                pre->next = l2;              
                l2 = l2->next;
            }
            pre = pre->next;
        }
        pre->next = l1 ? l1 : l2;        
        return root->next;
    }
};

化简代码

减少生成中间变量。
击败100%

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        int size = lists.size();
        if (size == 0) {
            return nullptr;
        }
        if (size == 1) {
            return lists[0];
        }
        queue<ListNode*> waiting(deque<ListNode*>(lists.begin(), lists.end())); //将vector转为队列
        //如果队列元素大于1,则取出两个进行合并,合并后的链表继续添加到链表尾部
        while (waiting.size() > 1) {
            ListNode *l1 = waiting.front();
            waiting.pop();
            ListNode *l2 = waiting.front();
            waiting.pop();
            waiting.push(merge2(l1, l2));
        } 
        return waiting.front();
    }
    ListNode* merge2(ListNode *l1, ListNode *l2) {
        ListNode *root = new ListNode(0), *pre = root;        
        while (l1 && l2) {
            if (l1->val <= l2->val) {
                pre->next = l1;
                l1 = l1->next;
            } else {
                pre->next = l2;              
                l2 = l2->next;
            }
            pre = pre->next;
        }
        pre->next = l1 ? l1 : l2;        
        return root->next;
    }
};
posted @ 2020-04-26 20:39  Galaxy_hao  阅读(159)  评论(0编辑  收藏  举报