【困难】23-合并K个排序链表 Merge k Sorted Lists

题目

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

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

Example:

Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6

解法

方法一:逐一合并

解题思路

在21题(【简单】21-合并两个有序链表 Merge Two Sorted Lists)已经做过了两个有序链表的合并,所以每次将两个链表合并成一个新的链表,然后再把下一个链表与这个链表合并。

代码

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    if(l1 == NULL) return l2;
    if(l2 == NULL) return l1;
    ListNode head(0);
    ListNode *curr = &head;
    while(l1 != NULL || l2 != NULL){
        if(l1 == NULL) {curr->next = l2; return head.next;}
        if(l2 == NULL) {curr->next = l1; return head.next;}
        if(l1->val < l2->val){
            curr->next = l1;
            curr = curr->next;
            l1 = l1->next;
        }
        else{
            curr->next = l2;
            curr = curr->next;
            l2 = l2->next;
        }
    }
    return head.next;
}
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size() == 0) return NULL;
       ListNode *res = lists[0];
        for (int i = 1; i < lists.size(); ++i) {
            res = mergeTwoLists(res, lists[i]);
        }
        return res;
    }
};

方法二:分治与归并

解题思路

方法一是逐一将链表与已知的链表融合在一起,自然想到,我们可以每两个链表合并在一起,得到n/2个链表,然后重复过程,得到n/4个链表,一直到得到最后的链表,这是归并的思路,那么反过来就是,把一组链表分成两半,这最终的结果就是对这两半各自得到的链表的求合并结果,也就是分治的思想,分支代码在下面。

代码

class Solution {
 public:
     ListNode* mergeKLists(vector<ListNode*>& lists) {
         if(lists.size() == 0) return NULL;
         return distribute(lists, 0, lists.size()-1);        
     }
     ListNode* distribute(vector<ListNode*> lists, int left, int right){
         if(left < right){
             int mid = (left+right) / 2;
             return mergeTwo(distribute(lists, left, mid), distribute(lists, mid+1, right));
         }
         return lists[left];
     }
     ListNode* mergeTwo(ListNode* left, ListNode* right){
         ListNode* res = new ListNode(0);
         ListNode* curr = res;
         while(left != NULL && right != NULL){
             bool nextIsLeft = left->val < right->val;
             curr->next = nextIsLeft ? left : right;
             left = nextIsLeft ? left->next : left;
             right = nextIsLeft ? right : right->next;
             curr = curr->next;
         }
         curr->next = left == NULL ? right : left;
         return res->next;
     }
 };

方法三:优先队列

解题思路

优先队列会把更大优先级的元素排在前面,所以可以把链表中的元素作为优先级的值放入优先队列,也就是写一个比较的函数,让数字更小的具有更高的优先级,然后直接输出

代码

struct cmp{
    bool operator()(ListNode* l, ListNode* r){
        return l->val > r->val;
    }
};
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
       priority_queue<ListNode*, vector<ListNode*>, cmp> res;
        for(int i = 0; i < lists.size(); ++i){
            if(lists[i] != NULL){
                res.push(lists[i]);
            }
        }
        ListNode* start = new ListNode(0);
        ListNode *curr = start;
        ListNode *t = NULL;
        while(!res.empty()){
            t = res.top();
            res.pop();
            curr->next = t;
            if(t->next != NULL){
                res.push(t->next);
            }
            curr = curr->next;
        }
        return start->next;
    }
};
posted @ 2020-04-26 16:42  陌良  阅读(132)  评论(0编辑  收藏  举报