反转链表及合并两个有序链表的递归实现方法

1 篇文章 0 订阅
1 篇文章 0 订阅

关于力扣上面的两道链表的简单题运用递归的形式实现;

(1)给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例:1->2->3->4->5      反转后的输出结果为 5->4->3->2->1

分析:  看到这种题,大多数人想到的就是利用指针法,改变指针指向的顺序以此来达到逆转的方法,但其实这种题型也可以利用递归的方法实现,处理链表的很多问题都可以利用递归来解决,我们先来回顾一下何时才能使用递归。1、大问题能够拆解成多个子问题  2、子问题和大问题求解方式一样  3、存在最小子问题。很多人恐惧递归,无非是题目做少了或者是不想画图一步步分析,现在我带大家依次分析一下。

首先所给示例为:

 我们发现需要先将head和其后面的元素进行反转,我们再次作图观察发现现仍需反转head和head后一个元素的位置,与上一步情况相同:

我们再次分解此大问题得到一下情形:

 同样的,如上两图都与大问题情况相似,需逆转head结点和其后节点的位置,我们继续分析:

 我们发现当head结点只剩下最后一个时,是无法与后一个结点进行逆转的,此时我们发现存在最小子问题,通过以上分析,我们发现此题满足使用递归的三种条件,我们即可使用递归来求解此题。

递归的这个过程分为递和归两个步骤来完成我们先来分析递的过程,顾名思义,递这个过程就是将大问题拆解成小问题的过程,如上图所示,那么什么时候结束递的过程呢,就是达到了最小子问题,无法进行下一步递的过程,即head指针指向了5,此时反转5这个结点没有意义,即可跳出递的这个条件。接着分析下归的过程,归的过程就是将每个子问题按题意处理好,根据题意我们可以知道我们需将每个子问题都逆转,那么我们来分析逆转的这个操作该如何进行,下图选取一个子问题。

要将4,5这两个位置逆转,即是逆转他们的指针,将5的下一个位置指向4;那么我们就可以将指向4的head指针的next位置(即指向5的指针)的next指针指向4,然后再将指向4的head指针的next指针指向空,这样子问题的逆转就被解决了

分析完毕,现在我们可以写出代码

class Solution {

public:

    ListNode* reverseList(ListNode* head) 

    {

       //递归终止条件,如果当前没有元素或者只有一个元素时返回

       if(head==nullptr||head->next==nullptr)

       {

           return head;

       }

     //不断进行递归调用,返回反转的链表。p指向的是每次归的过程返回的最后一个结点

       ListNode *p=reverseList(head->next);

    //具体的反转步骤,归的过程需要做的事情

       head->next->next=head;

       head->next=nullptr;

    //最后返回p即可

       return p;

    }

};

以上反转链表的递归实现方法,下面写迭代的方法:

class Solution {
public:
    ListNode* reverseList(ListNode* head) 
    {
       ListNode *cur=nullptr;
       ListNode *prev=head;
       while(prev!=nullptr)
       {
           ListNode *p=prev->next;
           prev->next=cur;
           cur=prev;
           prev=p;
       }
       return cur;
    }
};

(2)将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例:1->2->4和1->3->4    合并后返回的结果是1->1->2->3->4->4

我们发现此题也满足递归的三种条件,1、大问题能够拆解成多个子问题  2、子问题和大问题求解方式一样  3、存在最小子问题。两个链表的合并可以分解成两个链表中每个元素之间的比较和合并,且求解方法同样相同,两条链表中的一条遍历完了即为终止条件,另一条链表的剩余部分即可直接插入到合并的链表后面。下面写出递归的代码:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {

           //终止条件 
        if (l1 == nullptr) {
            return l2;
        } else if (l2 == nullptr) {
            return l1;
        }

         //递归中比较两个链表中的元素值并且合并的步骤

         //如果L1中元素的值小于L2中元素的值,则保留下L1中元素的值,L1的下一个元素为L1-                   >next和L2元素值比较的最小值,L2同理。

          else if (l1->val < l2->val) {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        } else {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

下面写出迭代解决此题的代码:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* preHead = new ListNode(-1);

        ListNode* prev = preHead;
        while (l1 != nullptr && l2 != nullptr) {
            if (l1->val < l2->val) {
                prev->next = l1;
                l1 = l1->next;
            } else {
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }

        // 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
        prev->next = l1 == nullptr ? l2 : l1;

        return preHead->next;
    }
};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值