【剑指offer】链表03-JZ25 合并两个排序的链表

7 篇文章 0 订阅

题目

JZ25 合并两个排序的链表
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
数据范围: 0 ≤ n ≤ 1000,−1000≤节点值≤1000

要求:空间复杂度 O(1),时间复杂度 O(n)

如输入{1,3,5},{2,4,6}时,合并后的链表为{1,2,3,4,5,6},所以对应的输出为{1,2,3,4,5,6},转换过程如下图所示:
在这里插入图片描述

或输入{-1,2,4},{1,3,4}时,合并后的链表为{-1,1,2,3,4,4},所以对应的输出为{-1,1,2,3,4,4},转换过程如下图所示:

在这里插入图片描述

示例1
输入:{1,3,5},{2,4,6}
返回值:{1,2,3,4,5,6}
示例2
输入:{},{}
返回值:{}

解决

数组

思路

两个链表节点数据值放进数组里,对v进行从小到大排序。然后再创建一个链表,将数组值赋给这个链表。
感觉这个思路应该不太有效率。待我看看官方解题思路去(看了 果然我是个lj ┭┮﹏┭┮)。

步骤

1.惯例先要考虑到链表是否为空的情况。如果链表1为空返回链表2,反之。如果都为空,返回空。
2.创建数组(vector也可以),当1不为空,将1节点数值存进链表,2也是。
3.对数组排序
4.新建链表,将数组值逐一赋给链表节点数值。

双指针迭代

递归(recursion):递归常被用来描述以自相似方法重复事物的过程,在数学和计算机科学中,指的是在函数定义中使用函数自身的方法。(A调用A)
迭代(iteration):重复反馈过程的活动,每一次迭代的结果会作为下一次迭代的初始值。(A重复调用B)

作者:在彼处
链接:https://www.jianshu.com/p/32bcc45efd32
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路

利用归并排序的思想,每次比较两个头部,从中取出最小的元素,然后依次往后。这样两个链表依次往后,我们肯定需要两个指针同方向访问才能实现
在这里插入图片描述

步骤

1.惯例先要考虑到链表是否为空的情况。如果链表1为空返回链表2,反之。如果都为空,返回空。
2.新建一个表头当做排序后的链表的标头,新建两个指针分别指向两条链表的头部。
3.在两条链表都不为空的情况下,遍历两个指针判断当前节点值的大小,小的那个节点地址存入新链表表头的next里,然后数值小的指针偏移继续比较。
4.最后肯定有一条链表会有剩余节点,这些节点的值都比前面的大,直接排在新链表后面就行了。

代码实现

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        //判断是否为null
        if(pHead1==NULL)
            return pHead2;
        if(pHead2==NULL)
            return pHead1;
        //创建新链表表头
        ListNode *pnew=new ListNode(0);//值为0的节点
        //创建一个节点指针指向头节点,后续做偏移
        ListNode *cur=pnew;
        //如果两个链表都不为空(有一个链表节点为空了就跳出循环)
        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)
        {
            cur->next=pHead1;
        }
        else
        {
            cur->next=pHead2;
        }
        //函数返回新链表(去掉表头(数值为0不属于原始两个链表))
        return pnew->next;              
    }
};

双指针递归

终止条件: 当一个链表已经因为递归到了末尾,另一个链表剩余部分一定都大于前面的,因此我们可以将另一个链表剩余部分拼在结果后面,结束递归。
返回值: 每次返回拼接好的较大部分的子链表。
本级任务:每级不断进入下一个较小的值后的链表部分与另一个链表剩余部分,再将本次的节点接在后面较大值拼好的结果前面。

思路

逐层递归,每层值小的那个指针后移递归,直到某一层链表next为空,next进入递归函数后,判断一个链表为空了。
然后返回另一个链表当前节点的地址 ,赋给上一层值最小的节点的pnext。逐渐跳出层层递归函数,将值大的节点的地址赋给值小的节点的指针域里,串起来。
也就是:
下一层值最小的节点的地址赋给当前层最小节点的后面,当前层值最小的节点地址赋给上一层值最小的节点后面,以此类推,从大的节点向小的节点串起来。
该方法不需要新创建一个链表。代码简单,但理解起来不容易。自己找了几篇文章和视频逐渐理解了些。

逐层深入(排序) 逐层返回(连接)
在这里插入图片描述
理解思路借鉴:
https://blog.csdn.net/qq_38737428/article/details/117329875
https://www.bilibili.com/video/BV1Lq4y1f7kn

步骤

1.惯例先要考虑到链表是否为空的情况。如果链表1为空返回链表2,反之。如果都为空,返回空。
2.比较两条链表节点数值,数值小的那个链表节点的下一个节点的指针域接收递归函数的返回值。然后返回这个数值小的节点。
3.逐层递归直到一条链表为null时开始返回跳出递归函数。
逐层递归,每层值小的那个指针后移递归,直到某一层链表next为空,next进入递归函数后,判断一个链表为空了。
然后返回另一个链表当前节点的地址 ,赋给上一层值最小的节点的pnext。逐渐跳出层层递归函数,将值大的节点的地址赋给值小的节点的指针域里,串起来。
4.最后形成一条完整的合并后的递增链表。
在这里插入图片描述

代码实现

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        //判断是否为null
        if(pHead1==NULL)
            return pHead2;
        if(pHead2==NULL)
            return pHead1;
        //判断两链表节点数值哪个数值小
        if(pHead1->val<pHead2->val)
        {
            pHead1->next=Merge(pHead1->next, pHead2);
            return pHead1;
        }
        else
        {
            pHead2->next=Merge(pHead1, pHead2->next);
            return pHead2;           
        }
        
    }
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值