三道题套路解决递归问题

递归算法详解 本篇博客的主要内容如下1. 什么是递归2. 递归三要素3. 递归的优缺点4. 递归的优化 1. 什么是递归     相信很多人开始学算法,第一个接触的就是递归,为什么要先学递归呢?这是因为递归是其他算法的基础,像深度优先搜索、分治算法、回溯算法都是在递归的基础上做出一些改进。那到底什么是递归呢?递归 = 递进 + 回归,递进的意思是把复杂的问题逐步的拆解成和原问题类似的子问题,直到我们一眼就能看出子问题的答案为止(也就是递归终止条件);而回归和递进正好相反,当我们求解了最简子问题后,我们就能求解上一层的子问 阅读详情

递归解题三部曲

何为递归?程序反复调用自身即是递归。

我自己在刚开始解决递归问题的时候,总是会去纠结这一层函数做了什么,它调用自身后的下一层函数又做了什么…然后就会觉得实现一个递归解法十分复杂,根本就无从下手。

相信很多初学者和我一样,这是一个思维误区,一定要走出来。既然递归是一个反复调用自身的过程,这就说明它每一级的功能都是一样的,因此我们只需要关注一级递归的解决过程即可。

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

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

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

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

一定要理解这3步,这就是以后递归秒杀算法题的依据和思路。

但这么说好像很空,我们来以题目作为例子,看看怎么套这个模版,相信3道题下来,你就能慢慢理解这个模版。之后再解这种套路递归题都能直接秒了。

例1:求二叉树的最大深度

先看一道简单的Leetcode题目: Leetcode 104. 二叉树的最大深度

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

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

 

 具体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评论区一样,很骚的几行代码搞定问题,让之后的新手看的一脸懵逼(这道题也是我第一次一行代码搞定一道Leetcode题):

class Solution {
    public int maxDepth(TreeNode root) {
        return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}

例2:两两交换链表中的节点

看了一道递归套路解决二叉树的问题后,有点套路搞定递归的感觉了吗?我们再来看一道Leetcode中等难度的链表的问题,掌握套路后这种中等难度的问题真的就是秒:Leetcode 24. 两两交换链表中的节点

直接上三部曲模版:

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

 

 附上Java代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
      	//终止条件:链表只剩一个节点或者没节点了,没得交换了。返回的是已经处理好的链表
        if(head == null || head.next == null){
            return head;
        }
      	//一共三个节点:head, next, swapPairs(next.next)
      	//下面的任务便是交换这3个节点中的前两个节点
        ListNode next = head.next;
        head.next = swapPairs(next.next);
        next.next = head;
      	//根据第二步:返回给上一级的是当前已经完成交换后,即处理好了的链表部分
        return next;
    }
}

 

例3:平衡二叉树

相信经过以上2道题,你已经大概理解了这个模版的解题流程了。

那么请你先不看以下部分,尝试解决一下这道easy难度的Leetcode题(个人觉得此题比上面的medium难度要难):Leetcode 110. 平衡二叉树

我觉得这个题真的是集合了模版的精髓所在,下面套三部曲模版:

  1. 找终止条件。 什么情况下递归应该终止?自然是子树为空的时候,空树自然是平衡二叉树了。

  2. 应该返回什么信息:

    为什么我说这个题是集合了模版精髓?正是因为此题的返回值。要知道我们搞这么多花里胡哨的,都是为了能写出正确的递归函数,因此在解这个题的时候,我们就需要思考,我们到底希望返回什么值?

    何为平衡二叉树?平衡二叉树即左右两棵子树高度差不大于1的二叉树。而对于一颗树,它是一个平衡二叉树需要满足三个条件:它的左子树是平衡二叉树,它的右子树是平衡二叉树,它的左右子树的高度差不大于1。换句话说:如果它的左子树或右子树不是平衡二叉树,或者它的左右子树高度差大于1,那么它就不是平衡二叉树。

    而在我们眼里,这颗二叉树就3个节点:root、left、right。那么我们应该返回什么呢?如果返回一个当前树是否是平衡二叉树的boolean类型的值,那么我只知道left和right这两棵树是否是平衡二叉树,无法得出left和right的高度差是否不大于1,自然也就无法得出root这棵树是否是平衡二叉树了。而如果我返回的是一个平衡二叉树的高度的int类型的值,那么我就只知道两棵树的高度,但无法知道这两棵树是不是平衡二叉树,自然也就没法判断root这棵树是不是平衡二叉树了。

    因此,这里我们返回的信息应该是既包含子树的深度的int类型的值,又包含子树是否是平衡二叉树的boolean类型的值。可以单独定义一个ReturnNode类,如下:

    class ReturnNode{
      boolean isB;
      int depth;
      //构造方法
      public ReturnNode(boolean isB, int depth){
        this.isB = isB;
        this.depth = depth;
      }
    }

  3. 本级递归应该做什么。 知道了第二步的返回值后,这一步就很简单了。目前树有三个节点:root,left,right。我们首先判断left子树和right子树是否是平衡二叉树,如果不是则直接返回false。再判断两树高度差是否不大于1,如果大于1也直接返回false。否则说明以root为节点的子树是平衡二叉树,那么就返回true和它的高度。

具体的Java代码如下:

class Solution {
    //这个ReturnNode是参考我描述的递归套路的第二步:思考返回值是什么
    //一棵树是BST等价于它的左、右俩子树都是BST且俩子树高度差不超过1
    //因此我认为返回值应该包含当前树是否是BST和当前树的高度这两个信息
    private class ReturnNode{
        boolean isB;
        int depth;
        public ReturnNode(int depth, boolean isB){
            this.isB = isB;
            this.depth = depth;
        }
    }
    //主函数
    public boolean isBalanced(TreeNode root) {
        return isBST(root).isB;
    }
    //参考递归套路的第三部:描述单次执行过程是什么样的
    //这里的单次执行过程具体如下:
    //是否终止?->没终止的话,判断是否满足不平衡的三个条件->返回值
    public ReturnNode isBST(TreeNode root){
        if(root == null){
            return new ReturnNode(0, true);
        }
        //不平衡的情况有3种:左树不平衡、右树不平衡、左树和右树差的绝对值大于1
        ReturnNode left = isBST(root.left);
        ReturnNode right = isBST(root.right);
        if(left.isB == false || right.isB == false){
            return new ReturnNode(0, false); 
        }
        if(Math.abs(left.depth - right.depth) > 1){
            return new ReturnNode(0, false);
        }
        //不满足上面3种情况,说明平衡了,树的深度为左右俩子树最大深度+1
        return new ReturnNode(Math.max(left.depth, right.depth) + 1, true);
    }
}

一些可以用这个套路解决的题

暂时就写这么多啦,作为一个高考语文及格分,大学又学了工科的人,表述能力实在差因此啰啰嗦嗦写了一大堆,希望大家能理解这个很好用的套路。

下面我再列举几道我在刷题过程中遇到的也是用这个套路秒的题,真的太多了,大部分链表和树的递归题都能这么秒,因为树和链表天生就是适合递归的结构。

我会随时补充,正好大家可以看了上面三个题后可以拿这些题来练练手,看看自己是否能独立快速准确的写出递归解法了。

Leetcode 101. 对称二叉树

Leetcode 111. 二叉树的最小深度

Leetcode 226. 翻转二叉树:这个题的备注是最骚的。Mac OS下载神器homebrew的大佬作者去面试谷歌,没做出来这道算法题,然后被谷歌面试官怼了:”我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。”

Leetcode 617. 合并二叉树

Leetcode 654. 最大二叉树

Leetcode 83. 删除排序链表中的重复元素

价值投资/指标选股(akshare) 利用akshare的数据源,可以获取所有的股票数据以及公开的财务数据,可以进行条件筛选,获取满足条件的股票。 这套模板可以用于价值投资,指标选股。选股周期为日线级别。然后结果可以邮箱发送。 import time import akshare as ak ## A 股上市公司的实时行情数据 stock_zh_a_spot_df = ak.stock_zh_a_spot() #print(stock_zh_a_spot_df) ##取前300测试 ##取前300测试 df_stock =... 阅读详情

相关推荐

【现代电路理论】【2】考尔法设计无源单口网络

夏 弥:其实你在冰面上看到鱼浮上来 明年冬天如果你还在那里,那鱼还是会上来换气 那时候你就可以带一把冰镐 把冰面砸开把鱼捞上来熬汤

痛苦的时候装出幸福相,这不是那么难做到的事 2886

看了就懂的递归解析

递归解题三部曲 何为递归?程序反复调用自身即是递归。 我自己在刚开始解决递归问题的时候,总是会去纠结这一层函数做了什么,它调用自身后的下一层函数又做了什么…然后就会觉得实现一个递归解法十分复杂,根本就无从下手。 相信很多初学者和我一样,这是一个思维误区,一定要走出来。既然递归是一个反复调用自身的过程,这就说明它每一级的功能都是一样的,因此我们只需要关注一级递归的解决过程即可。 如上图所示,我们需要关心的主要是以下三点: 整个递归的终止条件。 一级递归需要做什么? 应该返回给上一级的返回值是什么? 因此,也就

qq_36469679的博客 1728

别再乱改grub.cfg了!手把手教你用GRUB2自定义多系统启动菜单(含UEFI/BIOS双模式配置)

本文详细介绍了如何安全、高效地使用GRUB2自定义多系统启动菜单,涵盖UEFI/BIOS双模式配置。通过避免直接编辑grub.cfg文件,采用正确的配置方法和命令,帮助用户打造稳定且美观的启动环境,特别适合Linux多系统用户和开发者。

weixin_42553471的博客 590

递归解析

一、介绍 递归通过拆分成各个基本元素,然后再将基本元素组合运算结果作为下一层的中间值。 递归算法效率不高,并且代码可读性差,主要应用于数的遍历场景。 二、几种应用 1.斐波拉契数列 1)利用循环实现 num1 + num2 = num3 num2 + num3 = num4 num4 + num5 = num6 … 依此类推 可以总结出来 这里运算几次,就是循环几次,然后每次将两者运算结果作为中间...

我是传奇 2282

Java:使用Java调用打印机进行打印(JPG、PDF和Word三种文件格式)

目录 一、Java的打印简介 二、Java打印实现 2.1 JPG图片文件格式打印实现 2.2 PDF文件格式打印实现 2.3 Word文件格式打印实现 2.3.1 Word文件采用jacob插件进行打印实现。 2.3.2 先将word转化为pdf文件,然后打印pdf(lz使用) 三、总结 一、Java的打印简介 在我们的实际工作中,经常需要实现打印功能。但由于历史原因,Jav...

vatxiongxiaohui的专栏 8万+

LVGL9.2移植至正点原子阿波罗STM32F429开发板

LVGL(Light and Versatile Graphics Library)是一个开源的图形库,旨在为嵌入式系统提供高效、灵活的图形用户界面(GUI)解决方案。它具有小巧的内存占用和高性能的渲染能力,支持多种硬件平台,包括单片机、DSP 和 ARM 处理器等。LVGL 支持丰富的控件(如按钮、标签、图标、滚动条等),并提供强大的主题、样式和动画功能,使得开发者能够轻松设计出美观且响应迅速的界面。

m0_51149752的博客 3173

浅谈DNS递归解析和迭代解析之间的区别

递归解析”是最常见也是默认的一种解析方式。在这种解析方式中,如果客户端配置的本地域名服务器(Local DNS服务器)不能解析的话,则后面的查询过程全部由本地域名服务器代替DNS客户端进行查询,直到本地域名服务器从权威域名服务器得到了正确的解析结果,然后由本地域名服务器告诉DNS客户端查询的结果。在整个递归查询过程中,除一开始客户端向本地域名服务器发起查询请求外,其余各个环节均是以本地域名服务器为中心进行迭代查询,DNS客户端一直处于等待状态,直到本地域名服务器发回最终查询结果。

dzqxwzoe的博客 1365

智能座舱架构与芯片 - (3) 硬件篇 上

在了解智能座舱的基本架构之后,我们有必要针对智能座舱域的硬件平台,软件平台,SOC等进行逐一介绍。从它们的整体结构中去认识最新的智能座舱组成部件,以及主要功能等。如上图,是中央计算-区域控制架构下的智能座舱硬件平台框架图,其中,智能座舱控制器CDC挂载在以太网交换机上,与其他车控域VDC,自驾域ADC,网联设备5G+V2X等通过以太网实现数据交互。而智能座舱域的外部硬件设备还包含有连接子系统音频子系统摄像头子系统显示子系统存储子系统功能安全子系统等。

joanna_xiao的博客 2406

DNS安全概述

举个例子:现在很多服务都是托管在云上面,如果一个子域名曾经使用过,并且对外提供了服务,在下线服务的时候没有移除相应的DNS记录,同一个云上的其他用户就有可能使用原服务相同的公网IP。也有一些运营商,出于某种目的,会支持DNS流量,但是其提供的硬件资源不够,引起DNS解析异常缓慢甚至超时,严重影响用户体验。是一种由DNS客户端(通常是用户的应用程序,如一个浏览器)向本地DNS解析器发出解析请求,然后本地DNS解析器负责查询最终结果并将结果返回给客户端,而中间的所有查询请求都由本地DNS解析器代替客户端完成。

2401_84466361的博客 1735

LearningToRank(LTR)排序算法LGBMRanker的原理和使用

1. 写在前面 在最近新闻推荐的比赛中, 接触到了一个排序模型LGBMRanker, 该模型与普通的分类模型LGBMClassifier不太一样, 普通的分类模型在进行推荐的时候, 往往是先预测某个商品或者文章用户会不会点击, 也就是它的目标是预测用户点击某篇文章或者某个商品的概率, 然后根据这个概率值进行排序, 排完之后,把最靠前的几个返回回来给用户进行推荐。 而LGBRanker模型, 它不关心用户点击某篇文章的概率, 而是根据用户点击或者不点击的这个行为, 直接去预测最后商品或者文章的一个相对顺序,

Miracle8070 1万+

使用 Simulink 进行电力电子系统的小信号模型仿真

电力电子系统(Power Electronics System)包括各种功率转换器(如 DC-DC 转换器、逆变器等)。这些设备中的关键组件(如 MOSFET、IGBT、电容器、电感器等)不仅影响系统的性能,还直接关系到系统的稳定性、效率和可靠性。因此,在设计阶段进行详细的建模和仿真至关重要。小信号模型仿真的目的是通过线性化非线性系统来评估其动态特性,包括增益、相位裕度、带宽等指标。通过本教程,我们介绍了如何使用 Simulink 进行电力电子系统的小信号模型仿真。背景介绍。

xiaoheshang_123的博客 481

转载:三道题套路解决递归问题

文章目录递归解题三部曲例1:求二叉树的最大深度例2:两两交换链表中的节点例3:平衡二叉树一些可以用这个套路解决的题 2020-01-25更新: 说来惭愧,这是19年初写的文章了,那会的我还是不到50题的水平。当时是学了点后端的东西写了个博客网站,给它折腾上线后,就写了个文章放上去,顺便丢leetcode-cn上引流。没想到一年下来有好几万访问量,还有不少同学邮件联系我。 这一年来一直没有更新,最...

郎才女喵的博客 266

第11.4节 混合储能系统能量管理

混合储能系统(HESS)的能量管理策略采用分层架构实现多时间尺度优化:调度层(小时级)进行经济优化,协调层(秒级)基于频率分解分配功率,执行层(毫秒级)实现快速跟踪。深度强化学习(DRL)方法通过定义状态空间、动作空间和多目标奖励函数,能有效处理系统不确定性和多目标优化问题。HESS性能评估需综合技术指标(如调节性能Kp值、设备寿命指标)和经济指标(净现值NPV、平准化储能成本LCOS),并遵循"建模-仿真-实验"的闭环流程。

技术工作者 246

递归问题

非常好的一篇教程:三道题套路解决递归问题

weixin_43573233的博客 223

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

递归详解

相信不少同学和我一样,在刚学完数据结构后开始刷算法题时,遇到递归的问题总是很头疼,而一看解答,却发现大佬们几行递归代码就优雅的解决了问题。从我自己的学习经历来看,刚开始理解递归思路都很困难,更别说自己写了。 我一直觉得刷算法题和应试一样,既然是应试就一定有套路存在。在刷题中,我总结出了一套解决递归问题的模版思路与解法,用这个思路可以秒解很多递归问题。 递归解题三部曲 何为递归?程序反复调用自...

u011145904的博客 617

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

3道题彻底搞定:套路解决递归问题

前言 相信不少同学和我一样,在刚学完数据结构后开始刷算法题时,遇到递归的问题总是很头疼,而一看解答,却发现大佬们几行递归代码就优雅的解决了问题。从我自己的学习经历来看,刚开始理解递归思路都很困难,更别说自己写了。 我一直觉得刷算法题和应试一样,既然是应试就一定有套路存在。在刷题中,我总结出了一套解决递归问题的模版思路与解法,用这个思路可以秒解很多递归问题。 递归解题三部曲 何为递归?程序反复调用自...

comli_cn的博客 345

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

从三道LeetCode例题总结递归套路,解决递归问题

递归解题三部曲 何为递归?程序反复调用自身即是递归。 我自己在刚开始解决递归问题的时候,总是会去纠结这一层函数做了什么,它调用自身后的下一层函数又做了什么…然后就会觉得实现一个递归解法十分复杂,根本就无从下手。 相信很多初学者和我一样,这是一个思维误区,一定要走出来。既然递归是一个反复调用自身的过程,这就说明它每一级的功能都是一样的,因此我们只需要关注一级递归的解决过程即可。 如上图所示,我们需要关心的主要是以下三点: 整个递归的终止条件。 一级递归需要做什么? 应该返回给上一级的返回值是什么? 因此

mbytes的博客 536

3道Leetcode题,带你套路秒杀递归问题

前言 相信不少同学和我一样,在刚学完数据结构后开始刷算法题时,遇到递归的问题总是很头疼,而一看解答,却发现大佬们几行递归代码就优雅的解决了问题。从我自己的学习经历来看,刚开始理解递归思路都很困难,更别说自己写了。 我一直觉得刷算法题和应试一样,既然是应试就一定有套路存在。在刷题中,我总结出了一套解决递归问题的模版思路与解法,用这个思路可以秒解很多递归问题。 递归解题三部曲 何为递归?程序反复...

l384657597的博客 259

递归问题套路

标题三道题套路解决递归问题 递归解题三部曲 何为递归?程序反复调用自身即是递归。 我自己在刚开始解决递归问题的时候,总是会去纠结这一层函数做了什么,它调用自身后的下一层函数又做了什么…然后就会觉得实现一个递归解法十分复杂,根本就无从下手。 相信很多初学者和我一样,这是一个思维误区,一定要走出来。既然递归是一个反复调用自身的过程,这就说明它每一级的功能都是一样的,因此我们只需要关注一级递归的解决过程即可。 如上图所示,我们需要关心的主要是以下三点: 整个递归的终止条件。 一级递归需要做什么? 应该返回给上一

漏网小鱼的博客 424

转载 | 3道题彻底搞定:套路解决递归问题

转载文章网址:http://39.96.217.32/blog/4#comment-container 相信不少同学和我一样,在刚学完数据结构后开始刷算法题时,遇到递归的问题总是很头疼,而一看解答,却发现大佬们几行递归代码就优雅的解决了问题。从我自己的学习经历来看,刚开始理解递归思路都很困难,更别说自己写了。 我一直觉得刷算法题和应试一样,既然是应试就一定有套路存在。在刷题中,我总结出了一套解决递...

SurepMan的博客 238

力扣刷题篇之递归

​ 刷题按照:[力扣刷题攻略] Re:从零开始的力扣刷题生活 - 力扣(LeetCode),如图,因为是讲递归,所以所有题的首解都是给的递归。 递归不要看全过程,看一次递归就好,可以参考三道题套路解决递归问题 | lyl's blog (lyl0724.github.io) ​

m0_66076989的博客 1531

用递归解决链表问题

链表 递归

weixin_44628096的博客 994
上一篇: Spring之事务理解
下一篇: 23种设计模式
洋气月
博客等级 码龄8年 5386粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洋气月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值