【剑指offer】链表——016 合并两个排序的链表


在这里插入图片描述


题目内容

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

题目分析

这道题算是很基本的一道题,基本O(n)的复杂度就能完成,这道题的解题思想就是:在遍历两个链表的过程中,比较此时访问的结点,value较小的结点就加入到最后要返回的链表中。有所不同可能是从前合并结点还是从后合并结点,即递归非递归的写法。

解题

非递归解法

这种方法思路很简单,新创建一个链表,比较pHead1和pHead2,哪个结点的value小就插入新链表,如果某一个链表先被遍历完,那么另一个链表的剩下部分,直接插入新链表。
下面用表格演示一个过程,ListNode1: {1, 3, 5, 6)ListNode2: {2, 4},用加粗表示当前访问结点

状态ListNode1ListNode2newList
初始状态{1, 3, 5, 6}{2, 4}{}
1 < 2{3, 5, 6}{2, 4}{1}
3 > 2{3, 5, 6}{4}{1, 2}
3 < 4{5, 6}{4}{1, 2, 3}
5 > 4{5, 6}{}{1, 2, 3, 4}
ListNode2为NULL{}{}{1, 2, 3, 4, 5, 6}

代码

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        ListNode* newHead = new ListNode(1);
        ListNode* nowNode = newHead;
        if(pHead1 == NULL)
            return pHead2;
        if(pHead2 == NULL)
            return pHead1;
        while(pHead1 != NULL && pHead2 != NULL){
            if(pHead1->val <= pHead2->val){
                nowNode->next = pHead1;
                pHead1 = pHead1->next;
            }else{
                nowNode->next = pHead2;
                pHead2 = pHead2->next;
            }
            nowNode = nowNode->next;
        }
        if(pHead1 != NULL){
            nowNode->next = pHead1;
        }
        if(pHead2 != NULL){
            nowNode->next = pHead2;
        }
        return newHead->next;
    }
};

递归解法

这种思路其实和上一种方法差不多,只不过并没有显式地创建一个新的链表,而是因为递归的缘故从末尾开始比较,最后全部归到pHead1或者pHead2。
下面用表格演示一个过程,pHead1: {1, 3, 5, 6)pHead2: {2, 4},用加粗表示当前访问结点

状态pHead1pHead2说明
初始状态{1, 3, 5, 6}{2, 4}1 < 2,在pHead1进入递归,访问下一个结点
第1次递归{1, 3, 5, 6}{2, 4}3 > 2,在pHead2进入递归,访问下一个结点
第2次递归{1, 3, 5, 6}{2, 4}3 < 4,在pHead1进入递归,访问下一个结点
第3次递归{1, 3, 5, 6}{2, 4}5 > 4,在pHead2进入递归,访问下一个结点
第4次递归{1, 3, 5, 6}{2, 4}因为pHead2下一个结点为NULL,因此返回当前pHead1,结果给第3次递归的pHead2->next,返回上一层递归
第3次递归{1, 3, 5, 6}{2, 4 , 5, 6}因为从第2次递归进入第3次递归,是从pHead1进入的,所以返回当前pHead2,结果给第2次递归的pHead1->next,返回上一层递归
第2次递归{1, 3, 4, 5, 6}{2, 4 , 5, 6}因为从第1次递归进入第2次递归,是从pHead2进入的,所以返回当前pHead1,结果给第1次递归的pHead2->next,返回上一层递归
第1次递归{1, 3, 4, 5, 6}{2, 3, 4, 5, 6}因为进入第1次递归,是从pHead1进入的,所以返回当前pHead2,结果给初始的pHead1->next,返回上一层递归
结果pHead1{1, 2, 3, 4, 5, 6}{2, 3, 4, 5, 6}返回结果pHead1

表述的不太好,请结合代码观看。

代码

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        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;
        }
    }
};

进阶版非递归解法

这种方法的思路和第一种方法类似,但是我们不再是以创建一个新链表,而是在比较的过程中,把另一条链表合并到我指定的链表中。如果指定链表的下一个结点比另一条链表的结点小,那么指定链表继续向下访问链表;反之,另一个链表的当前结点插入到指定链表的当前结点和下一个结点之间

虽然听起来难度不大,但是加粗部分的代码实现逻辑较为繁杂,下面用图表示,请参照代码理解过程。
在这里插入图片描述
代码

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == NULL)
            return pHead2;
        if(pHead2 == NULL)
            return pHead1;
        ListNode* newHead;
        if(pHead1->val > pHead2->val){
            newHead = pHead1;
            pHead1 = pHead2;
            pHead2 = newHead;
        }
        newHead = pHead1;
        while(pHead1->next != NULL && pHead2 != NULL){
            if(pHead1->next->val > pHead2->val){
                ListNode* temp = pHead1->next;
                pHead1->next = pHead2;
                pHead2 = pHead2->next;
                pHead1 = pHead1->next;
                pHead1->next = temp;
            }else{
                pHead1 = pHead1->next;
            }
        }
        if(pHead2 != NULL){
            pHead1->next = pHead2;
        }
        return newHead;
    }
};

进阶版递归算法

思路与上一种方法一致,但是是递归实现,所以合并过程是从后往前进行的。

代码

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == NULL)
            return pHead2;
        if(pHead2 == NULL)
            return pHead1;
        if(pHead1 != NULL && pHead2 != NULL){
            if(pHead1->val > pHead2->val){
                ListNode* temp = pHead1;
                pHead1 = pHead2;
                pHead2 = temp;
            }
            pHead1->next = Merge(pHead1->next, pHead2);
        }
        return pHead1;
    }
};

以上思路为个人想法和网络各位大佬的题解的结合,欢迎讨论与指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值