23.合并K个升序链表-----力扣

一、题目:

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

题目链接

二、示例: 

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

三、分析: 

(1)什么是链表:

链表是一种常见的数据结构,它由一系列节点组成,这些节点通过指针连接。每个节点包含两部分:数据指向下一个节点的指针(next)。链表的特点是它的元素在内存不必连续存储,每个节点可以存储任意类型的数据,并且节点可以动态地添加和删除。

优点:

链表的优点是插入和删除操作的时间复杂度为O(1),而数组的插入和删除操作的时间复杂度为O(n),其中n为元素个数。

缺点:

链表的缺点是访问某个位置的元素需要遍历整个链表,时间复杂度为O(n),而数组的访问操作的时间复杂度为O(1)。

用途:

链表常用于需要频繁进行插入和删除操作的场景,例如实现队列、栈等数据结构,或者用于解决某些特定的问题。

由题可知,题目提供了一个链表数组,且它们都已经做了升序排列处理。让我们将它们合并在同一个升序链表中,并返回。由上面的题目和示例可知,只要我们将链表数组中的每个数组中的数据合并在一起、升序,就能得到正确答案。事实上,是这样吗?

(2)请看下面代码:
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists.length == 0) return null; //如果链表数组为空,返回
        ListNode ls=new ListNode(); //创建对象,用于获取数组中的对象
        ListNode ks=new ListNode(); //创建对象,用于存储结果
        List<Integer>p=new ArrayList<>(); //创建一个list集合,用于存储中途的各个数组元素
        int len=lists.length; //获取链表数组长度,用于循环
        for(int i=0;i<len;i++){
            ls=lists[i];
            while(ls!=null){
               p.add(ls.val); //添加元素
                ls=ls.next; //下一个对象
            }
        }
        if(p.isEmpty()) return null; //如果集合为空,说明数组里没有对象
        Collections.sort(p); //排序
        for(int i=p.size()-1;i>=0;i--){
            if(i==p.size()-1){ //插入最后一个元素,
                ks=new ListNode(p.get(i)); //不再需要next
            }else {
                ks=new ListNode(p.get(i),ks); //插入其它元素
            }
        }
        return ks; //返回结果
    }
}
(3)运行结果如图:

 


由上图结果可知,上述的解题思路是可以被采纳的。当然,除了用java语言来解决这道题外,还可以用c++来解决这道题。

 四、其它解题方法:

(1)如图是一个链表节点:


由上面对链表的介绍得知,链表每个节点包含两部分:数据指向下一个节点的指针(next)

(一)、数据部分就是用来存储数据的,支持任意类型的数据;

(二)、next指针部分用来指向下一个节点的,节点与节点之间的连接枢纽。

(2)分析: 

由上面我们已经对链表有了一定的了解。我们首先需要对题目提供的链表数组中的每个数据进行排序,在排序结束后,此时创建一个链表——用于存储结果。在进行将数据插入链表操作的时候,需要将已经插入的数据从原集合中删除,同时替换数据。因为用的是set有序集合来对数据进行排序(升序),每次取其头部数据(最小值)插入。最后,调整链表,同时插入已经替换的数据到链表中。

(3)请看下面代码: 
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        typedef pair<int,int>pir; //pair用于可以插入重复数据
        set<pir>s; //set用于排序
        for(int i=0;i<lists.size();i++){
            if(lists[i]==NULL)continue; //判空
            s.insert(pir(lists[i]->val,i)); //将链表中的值插入set中,i为第几个链表的序号
        }
        ListNode new_head,*p=&new_head,*q; //有头链表
        new_head.next=nullptr; //初始化头节点next指针
        while(s.size()){//集合元素不为空
            pir a=*s.begin(); //每一次取出头部数据
            s.erase(s.begin());//并且删除
            q=lists[a.second]; //表示第a.second个链表中的第一个节点(先取)
            lists[a.second]=lists[a.second]->next;//后将其替换
            p->next=q; //将q节点连接到p节点后面
            q->next=nullptr; //初始化q的next指针
            p=q; //p指向结果的最后一位,用于下次插入的节点将能够连接到q的next指针
            if(lists[a.second]){ //将第a.second个链表中的第一个节点插入,
                s.insert(pir(lists[a.second]->val,a.second)); //这个节点是已经替换掉的,不是原节点
            }
        }
        return new_head.next; //返回头节点
    }
};
(四)运行结果如图:

文章到此结束! 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值