递归算法讲解2

news2025/1/19 6:53:07

前情提要

上一篇递归算法讲解在这里
递归算法讲解(结合内存图)

没看过的小伙伴可以进去瞅一眼,谢谢!

递归算法的重要性

递归算法是非常重要的,如果想要进大厂,以递归算法为基础的动态规划是必考的,所以我们一定要好好学习递归算法!

本篇博客继续讲解一些递归的经典demo

demo01

递归实现求int类型的数组arr中前n项和,其中arr.length>=n,并且arr当中的元素总和在[-2147483648, 2147483647]之间

还记得递归三步走吗,我们来回顾一下

1. 明确递归的参数和返回值

很显然递归的参数有两个:数组arr + 要求和的序列长度n;
递归的返回值是我们求得的和,不会超过int类型的取值范围,所以数组求和很明显还是int

2. 明确递归的终止条件

我们已知的部分当中,n最小的情况就是递归的终止条件

我们目前已知的,sum(1)肯定是知道的,等于arr[0];sum(2)也是知道的,等于arr[0]+arr[1];

1比较小,所以n==1就是递归的终止条件

递归就是循环,递归的终止条件就是循环的中止条件

还有一些诸如i==j,i>j,都可能称为递归中止条件

3. 明确递归的单层递归逻辑

递归的单层递归逻辑是最难想到的

其实明确单层递归逻辑,很像是中学数学中,让我们求数列的通项公式,我们需要找规律

假设arr = {3,4,7,1,8,12,47……}

sum(1) = 3,sum(2) = 7,sum(3) = 14,sum(4) = 15……

那么sum(n) = ?

差不多是这样的一个过程

当然,本题目是比较简单的,一眼就能看出来,sum(n) = sum(n-1) + arr[n - 1]

递归难就难在,我们很多时候看不出来这个递归逻辑,此时就需要罗列出来找规律

从结束到开始,从部分到整体,从具象到抽象……

代码

	public static void main(String[] args) {
        int[] arr = {3, 4, 7, 1, 8, 12, 47};
        System.out.println(sum(arr, 5));
    }
    
	// 返回类型是int, 参数类型是arr和n
	public static int sum(int[] arr, int n) {
        // 前0项和显然是0
        if (n == 0) {
            return 0;
        }
        // 递归终止条件,返回arr[0]
        if (n == 1) {
            return arr[0];
        }
        // 单层递归逻辑,需要注意要加上arr[n-1]而不是arr[n],因为数组的下标是[0, arr.length - 1]
        return sum(arr, n - 1) + arr[n - 1];
    }

输出结果

在这里插入图片描述

demo02

递归实现折半查找

1. 明确递归的参数和返回值

递归参数是数组arr和要查找的值val

以及left,mid,right三个arr下标,用于判断后的移动

返回类型,可以返回找到的数值的下标(int),也可以什么都不返回(void)

2. 明确递归的终止条件

很明显是arr[i] = val,但是我们用谁去充当这个i指针呢?

熟悉折半查找的同学都知道,折半查找需要至少3个指针:left,mid,right

每一个指针都有可能在移动过程中直接指向val,我们应该选择谁当指针i呢?

很明显是mid,mid可以代表所有情况,left和right就不一定,而且可能陷入死循环

比如arr[mid]正好指向val,但是arr[left] != val,那么就会出现,arr[mid]既不大于val,也不小于

mid,但是无法跳出while循环的情况,也就是死循环

3. 明确递归的单层递归逻辑

当arr[mid] != val时执行递归

如果arr[mid]>val,说明val在mid左边,递归到左区间寻找;

如果arr[mid]<val,说明val在mid右边,递归到右区间寻找。

代码

public static void main(String[] args) {
        // 折半查找的前提是数组有序
        int[] arr = {1, 4, 34, 51, 432, 1111, 2776};

        halfSearch(arr, 4, 0, 3, arr.length - 1);

    }

    public static void halfSearch(int[] arr, int val, int left, int mid, int right) {
        if (val == arr[mid]) {
            System.out.println(val + "找到了,下标是:" + mid);
            return;        }

        if (val > arr[mid]) {
            halfSearch(arr, val, mid, (right + mid) / 2, right);// mid + 1也行
        } else if (val < arr[mid]) {// else即可
            halfSearch(arr, val, left, (mid + left) / 2, mid);// mid - 1也行
        }

    }

在这里插入图片描述

此时就会有聪明的小伙伴问了,如果没找到呢,你这种写法会栈溢出啊

其实我们只需要给left和right加一个判断就可以了

    public static void main(String[] args) {
        // 折半查找的前提是数组有序
        int[] arr = {1, 4, 34, 51, 432, 1111, 2776};

        halfSearch(arr, 432, 0, 3);

    }

    public static int halfSearch(int[] arr, int val, int left, int right) {
        int mid = (left + right) / 2;
        if (val == arr[mid]) {
            System.out.println(val + "找到了,下标是:" + mid);
            return mid;
        }
        if (left <= right) {
            if (val > arr[mid]) {
                return halfSearch(arr, val, mid + 1, right);// mid + 1也行
            } else {// else即可
                return halfSearch(arr, val, left, mid - 1);// mid - 1也行
            }
        } else {
            System.out.println(val + "没找到!");
            return -1;
        }

    }

如果left都大于right了,arr[mid]还是不等于val,那就说明真的没有这个值

demo03

二叉树的中序遍历

左,根,右---------------->中序遍历

如果一个要访问的结点,存在左子树,那么先访问左子树的最左结点

1. 明确递归的参数和返回值

递归参数是二叉树TreeNode,我们叫它root

返回类型,void即可,我们在遍历途中打印每一个结点的val值即可

2. 明确递归的终止条件

root不断遍历,只要不是空,就可以一直遍历

3. 明确递归的单层递归逻辑

在这里插入图片描述

上图这棵树,中序遍历的结果是7,37,13,46,3,19,76,48

因为树是链式结构,我们要遍历一棵树,只能先从根节点开始遍历,不能跨越访问,只能root.left.left……这样访问,这样就令很多同学犯难,我要怎么先从7开始访问呢?

这里其实非常简单,不要想的太复杂

我们仍然先从根节点开始访问,然后访问左子树,最后访问右子树

但是我们在访问左子树结束后再打印,我们只需要保证打印顺序是左根右即可

伪代码(不能运行!!!)

    public static void middle(TreeNode root) {
        if (root == null) {
            return;
        }
        
        // root不是null,先判断左孩子是不是null,再判断右孩子是不是null
        middle(root.left);
        System.out.println(left.val);
        middle(root.right);
        

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1568931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android安卓开发 - 简单介绍(一)

最近呢需要重构还有维护安卓项目&#xff0c;所以最近会从零开始梳理开发的一些知识点以及开发的内容 前面已经写了安装的教程&#xff0c;idea怎么安装&#xff0c;还有官方的开发工具Android Studio怎么安装 2024最新版Android studio安装入门教程&#xff08;非常详细&…

SpringBoot整合ELK8.1.x实现日志中心教程

目录 背景 环境准备 环境安装 1.JDK安装 2.安装Elasticsearch 3.安装zookeeper 4.安装Kafka 5.安装logstash 6.安装file beat 解决方案场景 1.日志采集 1.1 应用日志配置 1.1.1 创建logback-spring.xml文件 1.1.2 创建LoggerFactory 1.1.3 trace日志的记录用法 …

K8S- Deployment 的滚动更新 Rolling Update

滚动更新 这里的更新指的不是更新deployment 本身的属性(label/ replicas)等&#xff0c; 而是更新POD 的container 的版本 更新方法通常有两种 是直接update deployment配置&#xff0c; 注意只有update了template中的内容(与container相关) 才会触发更新用kubectl set ima…

C++ | Leetcode C++题解之第7题整数反转

题目&#xff1a; 题解&#xff1a; class Solution { public:int reverse(int x) {int rev 0;while (x ! 0) {if (rev < INT_MIN / 10 || rev > INT_MAX / 10) {return 0;}int digit x % 10;x / 10;rev rev * 10 digit;}return rev;} };

鸿宇多用户商城 scan_list.php SQL注入漏洞复现

0x01 产品简介 鸿宇多用户商城是一款支持各行业的多商家入驻型电商平台系统,商家版APP,微信商城,小程序及各种主流营销模块应有尽有,是一个功能强大的电子商务平台,旨在为企业和个人提供全面的在线购物解决方案。 0x02 漏洞概述 鸿宇多用户商城 scan_list.php 文件 data[fa…

Python 网络请求:深入理解Requests库

目录 引言 一、Requests库简介 二、安装与基本使用 三、requests库的特性与优势 四、requests库在实际应用中的案例 1.get请求 2.post请求 3.超时重试 4.headers设置 5.session会话 6.携带cookie​​​​​​​ 7.携带代理​​​​​​​ 8.携带身份认证​​​​​…

FLink学习(三)-DataStream

一、DataStream 1&#xff0c;支持序列化的类型有 基本类型&#xff0c;即 String、Long、Integer、Boolean、Array复合类型&#xff1a;Tuples、POJOs 和 Scala case classes Tuples Flink 自带有 Tuple0 到 Tuple25 类型 Tuple2<String, Integer> person Tuple2.…

InternLM2-lesson2作业

书生浦语大模型趣味 Demo 视频连接&#xff1a;https://www.bilibili.com/video/BV1AH4y1H78d/?vd_source902e3124d4683c41b103f1d1322401fa 目录 书生浦语大模型趣味 Demo一、基础作业二、进阶作业 一、基础作业 第一次执行&#xff1a; 第二次执行&#xff1a; 第一次执…

最新408试卷分析+备考经验分享

408出题再糟糕&#xff0c;你是不是还是要考&#xff1f; 别管出题人出多刁钻的题&#xff0c;大家拿到的卷子都是一样的&#xff0c;要难就都难&#xff0c;要刁钻就一起g... 所以再潜心钻研出题规律或出题套路&#xff0c;不如多花些时间去多复习巩固几遍知识点&#xff01…

Leetcode_2两数相加

文章目录 前言一、两数相加1.1 问题描述1.2 解法一&#xff1a;分别将链表转为数字&#xff0c;然后相加1.3 代码实现1.4 解法二&#xff1a;分别将对应位置数字相加1.5 代码实现 二、使用步骤1.引入库2.读入数据 前言 链表是一种物理内存非连续存储&#xff0c;非顺序的线性数…

深入理解C/C++的内存管理

在C和C中&#xff0c;高效的内存管理是编写性能优化和资源高效利用程序的关键。本文将深入探讨C/C内存管理的各个方面&#xff0c;包括内存的分布、C语言和C中的动态内存管理方式&#xff0c;以及new和delete操作符的使用 C/C内存分布 C和C程序的内存可以分为以下几个区域&…

【Linux】-进程知识铺垫①计算机硬件的组织:冯诺依曼体系结构详细解读②关于操作系统对软硬件及用户的意义

目录 ​编辑 1.关于计算机的体系结构 1.1 冯诺依曼体系结构的诞生 2.冯诺依曼体系结构 2.1 cpu:运算器&#xff1a;更多的是让cpu具有特殊的数据计算功能&#xff1a; 2.2 控制器 2.3输入设备 2.4输出设备 3.计算机各个硬件设备之间的关系 4.内存与计算机效率 5.关于为什么总说…

AI智能校色解决方案,专业级画质提升

由于拍摄环境、设备性能以及编辑经验等多种因素的影响&#xff0c;视频画质往往难以达到理想状态。这时&#xff0c;一款高效、智能的校色解决方案就显得尤为重要。美摄科技凭借深厚的图像处理技术和AI算法研发实力&#xff0c;推出了全新的AI智能校色解决方案&#xff0c;助力…

Kubernetes(k8s)核心资源解析:Pod详解

Kubernetes核心资源解析&#xff1a;Pod详解 1、什么是Pod&#xff1f;2、Pod 的组成3、Pod 如何管理多个容器4、Pod 的网络5、Pod 的存储方式6、Pod 的工作方式6.1 自主式 Pod6.2 监控和管理 Pod6.3 Pod 的创建流程 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

力扣热题100_链表_2_两数相加

文章目录 题目链接解题思路解题代码 题目链接 2. 两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 …

网络安全 | 什么是云安全?

关注WX&#xff1a;CodingTechWork 云安全-介绍 云安全是为了解决企业安全所面临的外部和内部威胁&#xff0c;它是一组程序和技术的集合。企业在实施其数字化转型策略&#xff0c;并将各种云端工具和服务纳入企业基础架构中时&#xff0c;需要云安全保障业务顺利进行。 云计…

ComfyUI ClipSeg插件报错- resize_image出错应该怎么办

上一篇刚介绍了这个插件&#xff0c;结果emm..很快发现事情并不简单...结果又报错了。 后台报错信息&#xff1a; Unused or unrecognized kwargs: padding. !!! Exception during processing !!! Traceback (most recent call last): File "F:\ComfyUI-aki\execution.p…

蓝桥杯练习笔记(十七)

蓝桥杯练习笔记&#xff08;十七&#xff09; 一、 输入样例 7 7 1000001 0100010 0010100 0001AAA 00010A0 00010A0 00010A0蓝桥官网题解&#xff1a; 该题解是用了三个循环分别对三个方向的相同字符的长度进行统计&#xff0c;找出最大长度&#xff0c;最后对找出的最长Y进…

Finite Element Procedures K.J.Bathe 【教材pdf+部分源码】|有限元经典教材 | 有限元编程

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

uni-app 实现仿微信界面【我的+首页聊天列表+长按菜单功能+添加菜单功能】+ 附源码

目录 【微信首页聊天列表】界面 【我的】界面 源代码&#xff1a; 文后附完整代码&#xff0c;支持一键导入 HBuilderX 示例体验 【微信首页聊天列表】界面 仿造【微信首页聊天列表 长按菜单功能 右上角添加按钮弹窗功能】&#xff0c;使用 uni-app 开发&#xff0c; 一…