leetcode刷题记录——递归

leetcode刷题记录——递归

——转自lyl’s blog的三道题套路解决递归问题(https://lyl0724.github.io/2020/01/25/1/)


文章目录

  递归解题三部曲

  Leetcode 104. 二叉树的最大深度

  Leetcode 24. 两两交换链表中的节点

  Leetcode 206. 反转链表


递归解题三部曲


只需要关注一级递归的解决过程即可。

在这里插入图片描述

(图片及内容均来自:https://lyl0724.github.io/2020/01/25/1/)

如上图所示,我们需要关心的主要是以下三点:

  1. 整个递归的终止条件。
  2. 一级递归需要做什么?
  3. 应该返回给上一级的返回值是什么?

因此,也就有了我们解递归题的三部曲:

  1. 找整个递归的终止条件:递归应该在什么时候结束?
  2. 找返回值:应该给上一级返回什么信息?
  3. 本级递归应该做什么:在这一级递归中,应该完成什么任务?

Leetcode 104. 二叉树的最大深度

题目很简单,求二叉树的最大深度,那么直接套递归解题三部曲模版:

  1. 找终止条件。 什么情况下递归结束?当然是树为空的时候,此时树的深度为0,递归就结束了。
  2. 找返回值。 应该返回什么?题目求的是树的最大深度,我们需要从每一级得到的信息自然是当前这一级对应的树的最大深度,因此我们的返回值应该是当前树的最大深度,这一步可以结合第三步来看。
  3. 本级递归应该做什么。 首先,还是强调要走出之前的思维误区,递归后我们眼里的树一定是这个样子的,看下图。此时就三个节点:root、root.left、root.right,其中根据第二步,root.left和root.right分别记录的是root的左右子树的最大深度。那么本级递归应该做什么就很明确了,自然就是在root的左右子树中选择较大的一个,再加上1就是以root为根的子树的最大深度了,然后再返回这个深度即可。

在这里插入图片描述

(图片及内容均来自:https://lyl0724.github.io/2020/01/25/1/)

具体Java代码如下:

class Solution {
    public int maxDepth(TreeNode root) {
        //终止条件:当树为空时结束递归,并返回当前深度0
        if(root == null){
            return 0;
        }
        //root的左、右子树的最大深度
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);
        //返回的是左右子树的最大深度+1
        return Math.max(leftDepth, rightDepth) + 1;
    }
}

Leetcode 24. 两两交换链表中的节点

三部曲模板:

  1. 找终止条件。 什么条件下终止?没得交换的时候,递归就终止了呗。因此当链表只剩一个节点或者没有节点的时候,自然递归就终止了。
  2. 找返回值。 我们希望向上一级返回什么信息?由于我们的目的是两两交换链表中相邻的节点,因此自然希望交换给上一级递归的是已经完成交换处理,即已经处理好的链表。
  3. 本级递归应该做什么。 结合第二步,看下图!由于只考虑本级递归,所以这个链表在我们眼里其实也就三个节点:head、head.next、已处理完的链表部分。而本级递归的任务也就是交换这3个节点中的前两个节点,就很easy了。

在这里插入图片描述

(图片及内容均来自:https://lyl0724.github.io/2020/01/25/1/)

【自我体验】

先写出递归的框架:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if() return ;

        swapPairs();

        return;
    }
};
  • 我要给下一级传什么参数?一个ListNode* 类型的指针,因此这一级我要处理好链表并且返回一个指针;考虑第一层:什么条件下递归不会进行?head==NULL || head->next==NULL的时候,是不会进行到下一层;因此要保证进入到下一层,只能满足head != NULL || head->next != NULL;

  • 传递的参数是head;因此每一级我得到的就是head指针;第一级的时候,head指针指向第一个节点;那么后面的每一级,也应该保持如此;所以每一级我需要交换的就是如上图所示的head和next;

    • 一开始的写法:问题在于每一级之间会脱节;没有联系在一起;
    class Solution {
    public:
        ListNode* swapPairs(ListNode* head) {
            if(head == NULL || head->next == NULL) return head;
            ListNode *next = head->next;
            ListNode *tmp = head->next->next;
            next->next = head;
            head->next = tmp;
            swapPairs(tmp);
            return;
        }
    };
    
    • 改进后写法:要将每一级都联系在一起;如何?
      • 首先明确传给下一级的swapPairs应该是当前head->next->next;
      • 因为swapPairs()函数返回的也是一个指针,并且这个指针代表着从head->next->next到NULL的指针;因此,代码应像如下一样进行交换:(就是相当于tmp = swapPairs(head->next->next);
    • 最后:应该像上一级返回什么?应当明确,在本题中,如果到最后退出,一定是head == NULL || head->next == NULL;因此最后一定是head->next = NULL ;然后next->next = head;更改的最后是next;因此要把next返回到上面的节点,才能形成连接;
    class Solution {
    public:
        ListNode* swapPairs(ListNode* head) {
            if(head == NULL || head->next == NULL) return head;
    
            ListNode *next = head->next;
            head->next = swapPairs(next->next);
            next->next = head;
    
            return next;
        }
    };
    

Leetcode 206. 反转链表

代码:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL || head->next == NULL) return head;

        ListNode *cur = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        
        return cur;
    }
};

思路:

  • 因为要反转链表;因此我们要获取最后一个节点作为头节点,这里用cur表示最后一个节点的指针,每次返回cur,第一级返回cur作为头节点;
    • 因为最后一个节点会出现head->next == NULL;然后此时的head就是上一级的cur;也就是最后一个节点;
  • 那么每一级返回cur后,只是将此时这一级的head->next->next = head;(就是反转链表)
  • 整个的思路就是通过递归到最后一层,得到最后的头节点;然后一层一层往前推,每次都反转两个节点即可;
  • 要注意同时让当前结点的 next指针指向 NULL,从而实现从链表尾部开始的局部反转(防止链表循环,需要将head.next设置为空);

​ 2022/9/3

【题目还在补充…】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值