合并K个升序链表

题目

合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。

数据范围:节点总数满足 0≤n≤1050 \le n \le 10^50≤n≤105,链表个数满足 1≤k≤105 1 \le k \le
10^5 \ 1≤k≤105 ,每个链表的长度满足 1≤len≤200 1 \le len \le 200 \ 1≤len≤200
,每个节点的值满足 ∣val∣<=1000|val| <= 1000∣val∣<=1000 要求:时间复杂度
O(nlogk)O(nlogk)O(nlogk)

示例1

输入:
[{1,2,3},{4,5,6,7}]
返回值:
{1,2,3,4,5,6,7}

示例2

输入:
[{1,2},{1,4,5},{6}]
返回值:
{1,1,2,4,5,6}

解题思路

这道题看似很难,牛客网上定义的也是较难的题型,其实理解之后也没有特别难,只是使用了多次合并两个有序链表的方式。

我们会有一个链表的数组,要将所有的链表都合并成一个链表
第一想法就是,一个个去比,然后将小的数据不断地插入到链表中,但是这么实现的难度太大了,我们不知道数组当中到底有多少个链表,循环的次数难以确定。
那么如何将复杂的问题化简成简单的问题呢?
可以将链表的集合拆分正一对一对的链表对,我们每次只合并两个链表(这样操作起来就比较简单了)。
合并两个有序链表的代码如下:

ListNode* mergeTwoLists(ListNode* pHead1,ListNode* pHead2)
    {
    	//如果有一个链表为空,直接返回拎一个链表
        if(pHead1 == NULL) return pHead2;
        if(pHead2 == NULL) return pHead1;

		//添加一个头结点
        ListNode* res = new ListNode(0);
        ListNode* cur =res;
        
        //将链表的值一个一个的连到目标链表当中
        while(pHead1 && pHead2)
        {
            if(pHead1->val < pHead2->val)
            {
                cur->next = pHead1;
                pHead1 =pHead1->next;
            }
            else
            {
                cur->next = pHead2;
                pHead2 = pHead2->next;
            }
            cur = cur->next;
        }

		//将剩余的链表链到目标链表当中
        if(pHead1 != NULL) cur->next = pHead1;
        if(pHead2 != NULL) cur->next = pHead2;
        
        //返回合并的链表
        return res->next;
    }
那么新的问题有来了,我们如何将时间复杂度降到O(nlongK)呢?

这个时候让我想起了简单快速排序,快排的时间复杂度不就是O(nlogN)嘛。
那能不能仿照快排的方式,将链表的集合进行划分,然后递归的去归并呢?事实是可以的,我们从中间开始划分,不断地递归,知道我们的链表数只剩下两个或者一个的时候,进行合并,然后再不断地拼接,最终得到我们想要的链表

流程图:
在这里插入图片描述

看实现:

//划分合并区间
    ListNode* Partition(vector<ListNode*> &lists,int left,int right)
    {
        if(left > right)
        {
            return NULL;
        }
        else if(left == right)
        {
            return lists[left];
        }
        
        int mid = (right-left)/2+left;
        
        return mergeTwoLists(Partition(lists, left, mid), Partition(lists, mid+1, right));
    }

整体代码:

class Solution {
public:
    //合并两个链表
    ListNode* mergeTwoLists(ListNode* pHead1,ListNode* pHead2)
    {
        if(pHead1 == NULL) return pHead2;
        if(pHead2 == NULL) return pHead1;
        ListNode* res = new ListNode(0);
        ListNode* cur =res;
        
        while(pHead1 && pHead2)
        {
            if(pHead1->val < pHead2->val)
            {
                cur->next = pHead1;
                pHead1 =pHead1->next;
            }
            else
            {
                cur->next = pHead2;
                pHead2 = pHead2->next;
            }
            cur = cur->next;
        }
        if(pHead1 != NULL) cur->next = pHead1;
        if(pHead2 != NULL) cur->next = pHead2;
        
        return res->next;
    }
    
    //划分合并区间
    ListNode* Partition(vector<ListNode*> &lists,int left,int right)
    {
        if(left > right)
        {
            return NULL;
        }
        else if(left == right)
        {
            return lists[left];
        }
        
        int mid = (right-left)/2+left;
        
        return mergeTwoLists(Partition(lists, left, mid), Partition(lists, mid+1, right));
    }
    
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        return Partition(lists, 0, lists.size()-1);
    }
};
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现合并K个升序链表,我们可以考虑使用分治法,将K个链表划分为两个子问题,分别合并这两个子问题,然后不断递归下去。 具体实现过程如下: 1. 将K个链表按照长度平均划分为两个子问题,每个子问题递归调用合并函数,直到只剩下一个链表或两个链表。 2. 合并两个链表的过程可以使用归并排序中的合并函数,将两个链表合并一个升序链表。 3. 将合并后的链表返回,然后递归回去继续合并两个子问题的结果。 Java代码实现如下: ``` public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; } return mergeKLists(lists, 0, lists.length - 1); } private ListNode mergeKLists(ListNode[] lists, int left, int right) { if (left == right) { return lists[left]; } int mid = (left + right) / 2; ListNode l1 = mergeKLists(lists, left, mid); ListNode l2 = mergeKLists(lists, mid + 1, right); return mergeTwoLists(l1, l2); } private ListNode mergeTwoLists(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } if (l2 == null) { return l1; } if (l1.val < l2.val) { l1.next = mergeTwoLists(l1.next, l2); return l1; } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } } ``` 其中,`mergeKLists` 函数是递归调用的入口函数,它接收一个 `ListNode` 数组作为参数,表示要合并的K个链表。在函数中,我们首先判断链表数组是否为空或长度为0,如果是,则返回 `null`。否则,我们调用 `mergeKLists` 函数,将链表数组划分为两个子问题,然后递归调用 `mergeKLists` 函数,继续划分子问题,直到只剩下一个链表或两个链表。 在 `mergeKLists` 函数中,我们使用归并排序的思想,将两个链表合并一个升序链表。具体实现是在 `mergeTwoLists` 函数中,它接收两个链表作为参数,递归调用自身,将两个链表合并一个升序链表

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值