【leetcode日记】23.合并k个链表

题目

合并 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

肯定是不能所有的链表都合并到一条链上的,可以预见,如果这样的话会导致有一条特别长的链表。
这里能想到两种链条合并的方式。

  • 一是两两合并(类似淘汰赛一样),也可以理解成是分治的思想,比如8条链,合并变成4条、2条、1条,这样子操作的一个优点是能大概保证每一条链合并次数都大致相同,所以不容易出现那种特别长的链条,而且只需要写一个合并两条链的函数就可以了,实际实现也比较方便,下面代码中采用的就是这个方法,效率还行。时间复杂度也是O(kn*lgk)
  • 二是采用官方题解中的优先队列。我们需要维护当前每个链表没有被合并的元素的最前面一个,k个链表就最多有 k 个满足这样条件的元素,每次在这些元素里面选取 val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。这样需要维护一个队列,每次挑选出k个数中的最小值,这个挑选的方式也可以采用“分治”思想解决,不过肯定是要进行(k-1)次比较。时间复杂度是O(nk*lgk)

代码:

// merge2Lists,顾名思义,把两个链表合并到一起,需要考虑到各种可能的异常
struct ListNode* merge2Lists(struct ListNode* head1, struct ListNode* head2)
{
    struct ListNode * head = NULL;
    struct ListNode * tail = NULL;

    if (head1 == NULL) {
        return head2;
    }

    if (head2 == NULL) {
        return head1;
    }

    if (head1->val <= head2->val) {
        head = tail = head1;
        head1 = head1->next;
    } else {
        head = tail = head2;
        head2 = head2->next;
    }

    while (1) {
        if ((head1 == NULL) && (head2 != NULL)) {
            tail->next = head2;
            head2 = NULL;
            break;
        }
        if ((head2 == NULL) && (head1 != NULL)) {
            tail->next = head1;
            head1 = NULL;
            break;
        }

        if (head1->val <= head2->val) {
            tail->next = head1;
            tail = head1;
            head1 = head1->next;            
        } else {
            tail->next = head2;
            tail = head2;
            head2 = head2->next;
        }
    }

    return head;
}

struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    int left = 0;
    int right = 0;
    int count = 0;

    if (listsSize <= 0) {
        return NULL;
    }

    do {
        count = 0;
        left = 0;
        right = listsSize-1;
        while (left < right) {
            lists[count++] = merge2Lists(lists[left++], lists[right--]);
        }   
        listsSize = (left == right)? left+1:left;
    } while (listsSize != 1);

    return lists[0];
}

运行结果:

运行结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邵政道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值