【LeetCode】23. 合并K个排序链表 结题报告 (C++)

原题地址:https://leetcode-cn.com/problems/merge-k-sorted-lists/description/

题目描述:

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

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6
解题方法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        int n = lists.size();
        if(n == 0) return NULL;
        ListNode* ans = lists[0];
        ListNode* pre;
        ListNode* p;
        ListNode* q;
        for(int i = 1; i < n; i ++){
            ListNode* pre;
            p = ans;
            q = lists[i];
            if(!ans){
                ans = lists[i];
                continue;
            }
            if(!lists[i]){
                continue;
            }
            if(ans->val <= lists[i]->val){
                pre = ans;
                p = p->next;
            }
            else{ 
                pre = lists[i];
                ans = pre;
                q = q->next;
            }
            while(p && q){
                if(p->val <= q->val){
                    pre->next = p;
                    p = p->next;
                }
                else{
                    pre->next = q;
                    q = q->next;
                }
                pre = pre->next;
            }
            if(p){
                pre->next = p;
            }
            if(q){
                pre->next = q;
            }
        }
        return ans;
    }
};

方法用的不怎么样,时间复杂度较大。

学习使用小根堆的方法,原文地址:https://blog.csdn.net/gatieme/article/details/51097730

class Comp
{
 public:
    bool operator() (const ListNode* left, const ListNode* right) const
    {
        return (left->val > right->val);
    }
};

class Solution
{
public:
    ListNode* mergeKLists(vector<ListNode*>& lists)
    {

        /// 将空链表
        vector<ListNode*>::iterator it = lists.begin();
        while(it != lists.end())
        {
            if(*it == NULL)
            {
                lists.erase(it);
            }
            else
            {
                ++it;
            }
        }
        if(lists.size( ) == 0)
        {
            return NULL;
        }

        ListNode *head = NULL;
        ListNode *curr = NULL;
        //  首先构造一个小顶堆
        //  这个操作会对lists中每个链表的第一个元素组成的序列建立一个堆
        make_heap(lists.begin( ), lists.end( ), Comp( ));
        while(lists.size() > 0)
        {

            //  堆顶的元素就是最小的元素
            ListNode *smallNode = lists[0];


            //  将smallNode插入到新链表中
            if(head == NULL)
            {
                curr = smallNode;
                head = smallNode;
            }
            else
            {
                curr->next = smallNode;
                curr = curr->next;
            }

            //  将最小的元素弹出


            //  BUG, 不能简单的使用pop操作,
            //  因为数据结构是链表不是数组
            //  如果将首指针弹出后, 会丢失整个单链表
            //  我们期待做的仅仅是需改指针的指向
            //  因此可以这么处理
            //  当链表中仍然有元素时, 仅仅修改首元素指针的指向
            //  只有当当前链表无其他元素时, 可直接弹出

            //pop_heap把堆顶元素取出来,放到了数组或者是vector的末尾,用原来末尾元素去替代,
            pop_heap(lists.begin( ), lists.end( ), Comp( ));
            //  此时smallNode被交换到了末尾

            if(lists[lists.size( ) - 1]->next == NULL)       //  如果当前链表已经没有其他元素了那么可以直接弹出
            {

                lists.pop_back( );               //  将为指针弹出后,相当于把整个单链表从lists中删除
            }
            else            //  当前最小元素所在的链表仍有其他元素, 仅仅修改首元素的指向
            {
                //  使用二重指针修改其指向或者直接用list[0]修改
                //ListNode **node = &lists[0];
                //*node = (*node)->next;
                lists[lists.size( ) - 1] = lists[lists.size( ) - 1]->next;

                push_heap(lists.begin( ), lists.end( ), Comp( ));

            }


        }

        return head;

    }
};

学习C++堆的用法:https://blog.csdn.net/flyyufenfei/article/details/78175511

在STL中,heap是算法的形式提供给我们使用的。包括下面几个函数:

  • make_heap: 根据指定的迭代器区间以及一个可选的比较函数,来创建一个heap. O(N) 默认的为大根堆

  • push_heap: 把指定区间的最后一个元素插入到heap中. O(logN)

  • pop_heap: 弹出heap顶元素, 将其放置于区间末尾. O(logN)

  • sort_heap:堆排序算法,通常通过反复调用pop_heap来实现. N*O(logN)

C++11加入了两个新成员:

  • is_heap: 判断给定区间是否是一个heap. O(N)

  • is_heap_until: 找出区间中第一个不满足heap条件的位置. O(N)

因为heap以算法的形式提供,所以要使用这几个api需要包含 #include <algorithm>


猜你喜欢

转载自blog.csdn.net/qq_32805671/article/details/80055058