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;
        }
    };
    
  • 相关阅读:
    Linux常用命令(5)--SSH访问远程服务器、SCP服务器间文件拷贝
    【转载】善用工具(1)--Mac版UltraEdit编辑器破解方法
    Linux常用命令(4)--善用"help"、"man在线帮助文档",轻松搞定系统命令
    Linux常用命令(3)--文件管理(查看文件大小权限信息、修改文件所属用户和操作权限、压缩解压文件)
    Linux常用命令(2)--vi (vim)文本编辑工具
    Linux常用命令(1)--用户管理(添加用户、修改密码、授予root权限)
    30分钟掌握ES6/ES2015核心内容(下)
    30分钟掌握ES6/ES2015核心内容(上)
    99%的人都理解错了HTTP中GET与POST的区别
    js中const,var,let区别
  • 原文地址:https://www.cnblogs.com/galaxy-hao/p/12782099.html
Copyright © 2011-2022 走看看