leetcode23. 合并K个排序链表  hard

25 篇文章 0 订阅
19 篇文章 0 订阅

leetcode23. 合并K个排序链表  hard          

题目描述:

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

解题思路:

两种方法的复杂度都是 O(nklogk)

方法1: 分治

不停的对半划分,比如k个链表先划分为合并两个k/2个链表的任务,再不停的往下划分,直到划分成只有一个或两个链表的任务,开始合并。举个例子来说比如合并6个链表,那么按照分治法,我们首先分别合并0和3,1和4,2和5。这样下一次只需合并3个链表,我们再合并1和3,最后和2合并就可以了。代码中的k是通过 (n+1)/2 计算的,这里为啥要加1呢,这是为了当n为奇数的时候,k能始终从后半段开始,比如当n=5时,那么此时k=3,则0和3合并,1和4合并,最中间的2空出来。当n是偶数的时候,加1也不会有影响,比如当n=4时,此时k=2,那么0和2合并,1和3合并,完美解决问题。

方法2:最小堆

用了最小堆这种数据结构,我们首先把k个链表的首元素都加入最小堆中,它们会自动排好序。然后我们每次取出最小的那个元素加入我们最终结果的链表中,然后把取出元素的下一个元素再加入堆中,下次仍从堆中取出最小的元素做相同的操作,以此类推,直到堆中没有元素了,此时k个链表也合并为了一个链表,返回首节点即可。

 tips:priority_queue<ListNode*,vector<ListNode*>,decltype(cmp)> pq(cmp); //注意写法

方法1代码:

/**
 * 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 nullptr;
        
        while(n>1){
            int k=(n+1)/2;  // 假如总数是奇数个 让中间这个不参与merge
            for(int i=0;i<n/2;++i){
                lists[i]=merge2lists(lists[i],lists[i+k]);
            }
            n=k;
        }          // 这一部分是精华
        
        return lists[0];
        
    }
    
    
    ListNode * merge2lists(ListNode *head1,ListNode *head2){
        if(!head1)
            return head2;
        if(!head2)
            return head1;
        ListNode dummy(0);
        ListNode *cur=&dummy;
        while(head1 && head2){
            if(head1->val<head2->val){
                cur->next=head1;
                head1=head1->next;
            }
            
            else{
                cur->next=head2;
                head2=head2->next;
            }
            
            cur=cur->next; 
        }
        
        if(head1)
            cur->next=head1;
        if(head2)
            cur->next=head2;
        return dummy.next;
    }
    
    
};

方法2代码:

/**
 * 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) {
        if(lists.empty())
            return nullptr;
        
        auto cmp=[]( ListNode *&a, ListNode *&b){
            return a->val>b->val;  //因为要小顶堆, false的优先级高
        };
        
        priority_queue<ListNode*,vector<ListNode*>,decltype(cmp)> pq(cmp); //注意写法
        
        for(auto i:lists){
            if(i!=nullptr)
                pq.push(i);
        }
        
        ListNode dummy(0);
        ListNode *pre=&dummy;
        ListNode *cur=nullptr;
        while(pq.size()){
            cur=pq.top();
            pq.pop();
            pre->next=cur;
            if(cur->next) pq.push(cur->next);
            pre=pre->next;
        }
        
        return dummy.next;
        
        
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值