zoukankan      html  css  js  c++  java
  • LeetCode 23

    一、问题描述

    Description:

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

    合并 k 个有序链表。


    二、解题报告

    解法一:两两合并

    由于前面刚刚做过《LeetCode 21 - Merge Two Sorted Lists》,看到这个题的第一反应就是两两合并,还可以直接调用mergeTwoLists()

    class Solution {
    public:
        /**
         * 合并两个有序链表
         */
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
            ListNode* head = new ListNode(0);
            ListNode* p = head;
            while(l1!=NULL && l2!=NULL) {
                if(l1->val < l2->val) {
                    p->next = l1;
                    l1 = l1->next;
                }
                else {
                    p->next = l2;
                    l2 = l2->next;
                }
                p = p->next;
                p->next = NULL;
            }
    
            if(l1!=NULL)
                p->next = l1;
            if(l2!=NULL)
                p->next = l2;
    
            return head->next;
        }
    
        /**
         * 合并k个有序链表:两两合并,直到最终变成一个。
         */
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            if(lists.empty())
                return NULL;
            ListNode* node = lists[0]; 
            for(int i=1; i<lists.size(); ++i)
                node = mergeTwoLists(node, lists[i]);
    
            return node;
        }
    };

    这种方法 超时 了!!!


    解法二:堆

    我们知道对于一个大根堆/小根堆,堆顶元素就是最大/最小值。本解法使用堆就是为了利用它的这个性质,思路就是:

    • 首先把 k 个链表的首节点看作一个集合,对其建堆;
    • 然后取出堆顶的节点,链接到结果链表上;
    • 将取出节点的下一个节点入堆,直到所有链表都完成为止。

    这里我们直接使用 C++ STL 的heap算法,它提供了三个主要的操作:

    1. make_heap():将一段现有的数据转化为一个堆,默认创建 max heap。
    2. push_heap():这个方法其实就是执行一个向上调整的操作。所以在向堆中插入元素时,必须先将新元素插入到容器的尾部,再对该容器执行push_heap作调整以保持堆的性质。
    3. pop_heap():这个方法不会移除堆顶元素,只是将堆顶元素转移到容器的尾部,所以在pop_heap后通常还要执行相应容器的 pop 方法作移除。
     class cmp {
     public:
         bool operator()(ListNode* p1, ListNode* p2) const {
            return p1->val > p2->val;
         }
     }; 
    
    class Solution {
    public:
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            vector<ListNode*>::iterator beg = lists.begin();
            for( ; beg!=lists.end(); ) {                        // 先移除lists中的空链表
                if(*beg == NULL)
                    beg = lists.erase(beg);
                else
                    ++beg;
            }
            if(lists.empty())                                   // 如果lists为空
                return NULL;
    
            make_heap(lists.begin(), lists.end(), cmp());       // 建小根堆
            ListNode* head = new ListNode(0);
            ListNode* p = head;
            while(!lists.empty()) {
                p->next = lists.front();                        // 第一个结点就是堆的根节点
                p = p->next;
                pop_heap(lists.begin(),lists.end(), cmp());     // pop操作将堆的根节点放到容器尾部
                lists.pop_back();                               // 移除之
                if(p->next != NULL) {
                    lists.push_back(p->next);                   // 先将新元素插入容器尾部
                    push_heap(lists.begin(),lists.end(),cmp()); // push_heap操作进行调整
                }
            }
            return head->next;
        }
    };

    注意,在使用自定义的比较类(comparator)时,make_heap()push_heap()pop_heap()要保持一致。


    解法三:优先级队列

    C++ STL 还提供了一个priority_queue(优先级队列),顾名思义,它是一个拥有权值观念的队列。

    • 它是队列,所以只能在底端加入元素,从顶端取出元素。
    • 它带有权值观念,所以其中的元素并非依照 push 的次序排列,而是依照权值排列,每次 pop 出权值最高的元素。

    priority_queue其实就是调用上面讲到的make_heap()push_heap()pop_heap()实现的,所以它的底层就是基于heap。只不过经过封装以后,使用更加方便了。

     class cmp {
     public:
         bool operator()(ListNode* p1, ListNode* p2) const {
            return p1->val > p2->val;
         }
     }; 
    
    class Solution {
    public:
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            vector<ListNode*>::iterator beg = lists.begin();
            for( ; beg!=lists.end(); ) {    // 先移除lists中的空链表
                if(*beg == NULL)
                    beg = lists.erase(beg);
                else
                    ++beg;
            }
    
            if(lists.empty())               // 如果为空,返回NULL
                return NULL;
    
            priority_queue<ListNode*,vector<ListNode*>,cmp> q(lists.begin(), lists.end());  // 优先级队列
            ListNode* head = new ListNode(0);
            ListNode* p = head;
            while(!q.empty()) {
                p->next = q.top();
                p = p->next;
                q.pop();
                if(p->next != NULL)
                    q.push(p->next);
            }
            return head->next;
        }
    };





    LeetCode答案源代码:https://github.com/SongLee24/LeetCode


  • 相关阅读:
    JMeter学习-016-思路篇之-山重水复柳暗花明
    JMeter学习-015-JMeter 断言之-Bean Shell Assertion
    JMeter学习-014-JMeter 配置元件实例之
    Fiddler-008-简单模拟性能测试
    Fiddler-007-修改HTTP请求响应数据
    Fiddler-006-修改HTTP请求参数
    JMeter学习-013-JMeter 逻辑控制器之-如果(If)控制器
    JMeter学习-012-JMeter 配置元件之-HTTP Cookie管理器-实现 Cookie 登录
    JMeter学习-011-JMeter 后置处理器实例之
    JMeter学习-010-JMeter 配置元件实例之
  • 原文地址:https://www.cnblogs.com/songlee/p/5738043.html
Copyright © 2011-2022 走看看