zoukankan      html  css  js  c++  java
  • 【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;
        }
    };
    
  • 相关阅读:
    异步底层代码实现邮件发送
    MongoDB+Echarts+DWebSocket
    celery定时任务+redis有序集合实现实时访问人数
    位运算+数据库两种方式实现中间件权限操作
    cocoapod 引入url
    pdf转xml
    Flutter项目安卓下载地址
    ios Mac 利用SVN进行cocoapod私有库的使用
    KVO
    类别和类扩展的区别
  • 原文地址:https://www.cnblogs.com/galaxy-hao/p/12782099.html
Copyright © 2011-2022 走看看