23合并K个排序链表

一、前言

分类:Divide and Conquer。

问题来源LeetCode 23 难度:困难。

问题链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/

 

二、题目

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

示例1:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

三、思路

这里提供两种解决方法

方法一:分治合并

方法二:优先队列合并

 

四、编码实现

//==========================================================================
/*
* @file    : 023_MergeKLists.h
* @label   : Divide and Conquer
* @blogs   : https://blog.csdn.net/nie2314550441/article/details/107424030
* @author  : niebingyu
* @date    : 2020/07/16
* @title   : 23.合并K个排序链表
* @purpose : 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
*
* 示例:
* 输入:
* [
*   1->4->5,
*   1->3->4,
*   2->6
* ]
* 输出: 1->1->2->3->4->4->5->6
* 
*
* 来源:力扣(LeetCode)
* 难度:困难
* 链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/
*/
//==========================================================================
#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <assert.h>
using namespace std;

#define NAMESPACE_MERGEKLISTS namespace NAME_MERGEKLISTS {
#define NAMESPACE_MERGEKLISTSEND }
NAMESPACE_MERGEKLISTS

struct ListNode 
{
    int val;
    ListNode* next;
    ListNode(int x=0, ListNode * nt = NULL) : val(x), next(nt) {}
};

// 方法一,逐个合并
class Solution_1 
{
public:
    ListNode* mergeTwoLists(ListNode*a, ListNode*b) 
    {
        if (!a) return b;
        if (!b) return a;

        ListNode *dummyHead = new ListNode(0);
        ListNode *cur = dummyHead;
        ListNode *ap = a, *bp = b;

        while (ap && bp) 
        {
            if (ap->val > bp->val) 
            {
                cur->next = bp;
                bp = bp->next;
            } 
            else 
            {
                cur->next = ap;
                ap = ap->next;
            }
            cur = cur->next;
        }

        cur->next = ap ? ap : bp;
        return dummyHead->next;
    }

    ListNode* merge(vector<ListNode*> &lists, int l, int r) 
    {
        if (l>r) return NULL;
        if (l==r) return lists[l];

        int mid = l + (r-l)/2;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid+1, r));
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) 
    {
        return merge(lists, 0, lists.size()-1);
    }
};

// 方法二,优先队列合并
class Solution_2 
{
public:
    struct Status 
    {
        int val;
        ListNode *ptr;
        bool operator < (const Status &rhs) const 
        {
            return val > rhs.val;
        }
    };

    priority_queue <Status> q;
    ListNode* mergeKLists(vector<ListNode*>& lists) 
    {
        for (auto node: lists) 
        {
            if (node) q.push({node->val, node});
        }

        ListNode head;
        ListNode *tail = &head;
        while (!q.empty()) 
        {
            auto f = q.top(); 
            q.pop();
            tail->next = f.ptr; 
            tail = tail->next;
            if (f.ptr->next) 
                q.push({f.ptr->next->val, f.ptr->next});
        }

        return head.next;
    }
};

以下为测试代码//
// 测试 用例 START
void test(const char* testName, vector<ListNode*>& lists, vector<int> expect)
{
    Solution_1 s;
    ListNode* ret = s.mergeKLists(lists);
    vector<int> result;
    while (ret)
    {
        result.push_back(ret->val);
        ret = ret->next;
    }

    if (result == expect)
        cout << testName << ", solution passed." << endl;
    else
        cout << testName << ", solution failed. " << endl;
}

// 测试用例
void Test1()
{
    ListNode* hd1_5 = new ListNode(5);
    ListNode* hd1_4 = new ListNode(4, hd1_5);
    ListNode* hd1 = new ListNode(1, hd1_4);

    ListNode* hd2_4 = new ListNode(4);
    ListNode* hd2_3 = new ListNode(3, hd2_4);
    ListNode* hd2 = new ListNode(1, hd2_3);

    ListNode* hd3_6 = new ListNode(6);
    ListNode* hd3 = new ListNode(2, hd3_6);

    // 只是测试用,懒得释放了
    vector<ListNode*> lists = { hd1, hd2, hd3 };
    vector<int> expect = { 1, 1, 2, 3, 4, 4, 5, 6};

    test("Test1()", lists, expect);
}

NAMESPACE_MERGEKLISTSEND
// 测试 用例 END
//
void MergeKLists_Test()
{
    cout << "------ start 23.合并K个排序链表 ------" << endl;
    NAME_MERGEKLISTS::Test1();
    cout << "------ end 23.合并K个排序链表 ------" << endl;
}

执行结果:

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值