leetcode 23. Merge k Sorted Lists(堆||分治法)

Merge k sorted linked lists and return it as one sorted list.

题意:把k个已经排好序的链表整合到一个链表中,并且这个链表是排了序的。

题解:这是一道经典好题,值得仔细一说。

有两种方法,假设每个链表的平均长度是n,那么这两种方法的时间复杂度都是O(nklogk)。

方法一

基本思路是:把k个链表开头的值排个序,每次取最小的一个值放到答案链表中,这次取完之后更新这个值为它后面的一个值。接着这么取一直到全部取完。那么每次更新之后怎么对当前这k个值重新排序以便知道当前最小的是谁呢?用优先队列(或者堆)来维护这k个值就好啦!

由于每个值都要取一次,一共取nk次。每次更新优先队列要logk的复杂度。所以总时间复杂度为O(nklogk);空间复杂度为优先队列所占空间,为O(k)。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution
{
public:
    struct cmp
    {
        bool operator() (const ListNode* a,const ListNode* b)
        {
            return a->val  > b->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists)
    {
        priority_queue<ListNode*, vector<ListNode*>, cmp>pq;
        for(auto i:lists)
        {
            if(i) //这句判断很有必要,不能把空的加入队列。比如这组数据:[[],[]]
            {
                pq.push(i);
            }
        }
        if(pq.empty())
        {
            return nullptr;
        }
        ListNode* ans = pq.top();
        pq.pop();
        ListNode* tail = ans;
        if(tail->next)
        {
            pq.push(tail->next);
        }
        while(!pq.empty())
        {
            tail->next = pq.top();
            tail = tail->next;
            pq.pop();
            if(tail->next)
            {
                pq.push(tail->next);
            }
        }
        return ans;
    }
};

方法二:

和方法一的思路不同:考虑分治的思想来解这个题(类似归并排序的思路)。把这些链表分成两半,如果每一半都合并好了,那么我就最后把这两个合并了就行了。这就是分治法的核心思想。

但是这道题由于存的都是指针,就具有了更大的操作灵活性,可以不用递归来实现分治。就是先两两合并后在两两合并。。。一直下去直到最后成了一个。(相当于分治算法的那棵二叉树从底向上走了)。

第一次两两合并是进行了k/2次,每次处理2n个值。

第二次两两合并是进行了k/4次,每次处理4n个值。

。。。

最后一次两两合并是进行了k/(2^logk)次,每次处理2^logK*N个值。

所以时间复杂度:

O((2N) * (K / 2) + (4N) * (K / 4) + (8N) * (K / 8) + .............. + (2^logK*N) * (K / (2 ^logK)) )=O( logK*KN)

空间复杂度是O(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) {
    if(lists.empty()){
        return nullptr;
    }
    while(lists.size() > 1){
        lists.push_back(mergeTwoLists(lists[0], lists[1]));
        lists.erase(lists.begin());
        lists.erase(lists.begin());
    }
    return lists.front();
    }
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
        if(l1 == nullptr){
            return l2;
        }
        if(l2 == nullptr){
            return l1;
        }
        if(l1->val <= l2->val){
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else{
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};
时间: 2024-11-05 11:46:46

leetcode 23. Merge k Sorted Lists(堆||分治法)的相关文章

[LeetCode]23. Merge k Sorted Lists

23. Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 给定k个排序了的链表,合并k个链表成一个排序链表. 本程序思路: 1)首先得到K个链表的长度和存在len中 2)从K个链表中找到值最小的那个节点,把该节点添加到合并链表中 3)重复len次即可把所有节点添加到合并链表中. 注意事项: 1)K个链表中有的

[LeetCode] 23. Merge k Sorted Lists 合并k个有序链表

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 与21. Merge Two Sorted Lists的拓展,这道题要合并k个有序链表,还是可以两两合并. 类似题目: [LeetCode] 21. Merge Two Sorted Lists 合并有序链表 原文地址:https://www.cnblogs.com/lightwindy/p/8512

leetCode 23. Merge k Sorted Lists (合并k个排序链表) 解题思路和方法

Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 思路:此题是由合并两个排序链表演化而来,刚开始,想法比较简单,像求最大公共前缀一样,逐一求解:但是最后超时,所以马上意识到出题方是为了使用归并和分治的方法,故重新写了代码. 代码一(超时未过): /** * Definition for singly-link

[LeetCode] 23. Merge k Sorted Lists ☆☆

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 解法1: 采用递归的方法,不管合并几个,归根到底还是需要两两合并. 首先想到的是前两个先合并,然后再跟第三个合并,然后第四个....但是这种做法效率不高. 换个思路,采用分治法,对数量超过2的任务进行拆分,直到最后只有一个或两个链表再进行合并.代码如下: /** * Definition for si

Java [leetcode 23]Merge k Sorted Lists

题目描述: Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 解题思路: 分而自治方法.将K个List不断地分解为前半部分和后半部分.分别进行两个List的合并.最后将合并的结果合并起来. 代码如下: /** * Definition for singly-linked list. * public class ListNode { * int va

[LeetCode]23. Merge k Sorted Lists合并K个排序链表

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. Example: Input: [   1->4->5,   1->3->4,   2->6 ] Output: 1->1->2->3->4->4->5->6 要合并K个排好序的链表,我用的方法是用一个优先队列每次存K个元素在队列中,根据优

LeetCode #23 Merge k Sorted Lists (H)

[Problem] Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. [Analysis] 这题一上来,就会想到之前做过的Merge Two Sorted Lists.但是如果单纯地不断将新的list merge进结果,复杂度是非常高的,因为仔细想想就会发现在这个过程中结果里已经merge过的元素需要被重新排序,而这一部分无用功是可以通过使用合理的技

LeetCode 23 Merge k Sorted Lists (C,C++,Java,Python)

Problem: Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. Solution: 采用胜者树的方法,胜者树介绍:胜者树,假如链表数组长度为n,链表元素总个数为k,那么时间复杂度为O(k*log(n)) 题目大意: 给定一个数组有序链表(数组元素可能为空),要求将这些链表合并为一个有序的链表. Java源代码(522ms): /** * Defi

23. Merge k Sorted Lists - LeetCode

Question 23.?Merge k Sorted Lists Solution 题目大意:合并链表数组(每个链表中的元素是有序的),要求合并后的链表也是有序的 思路:遍历链表数组,每次取最小节点 Java实现: public ListNode mergeKLists(ListNode[] lists) { ListNode preHead = new ListNode(0); ListNode minNode = getMinNode(lists); ListNode tmpNode =