【数据结构与算法】递归

一、什么是递归?

1.递归是一种非常高效、简洁的编码技巧,一种应用非常广泛的算法,比如DFS深度优先搜索、前中后序二叉树遍历等都是使用递归。
2.方法或函数调用自身的方式称为递归调用,调用称为递,返回称为归。

二、为什么使用递归?递归的优缺点?

1.优点:代码的表达力很强,写起来简洁。
2.缺点:空间复杂度高、有堆栈溢出风险、存在重复计算、过多的函数调用会耗时较多等问题。

三、什么样的问题可以用递归解决呢?

一个问题只要同时满足以下3个条件,就可以用递归来解决:
1.问题的解可以分解为几个子问题的解。何为子问题?就是数据规模更小的问题。
2.问题与子问题,除了数据规模不同,求解思路完全一样
3.存在递归终止条件


int f(int n) {if (n == 1) return 1;if (n == 2) return 2;return f(n-1) + f(n-2);
}

四、如何实现递归?

1.递归代码编写
递归代码最关键的是写出递推公式,找到终止条件

写递归代码的关键就是找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,然后再推敲终止条件,最后将递推公式和终止条件翻译成代码。
2.递归代码理解
编写递归代码的关键是,只要遇到递归,我们就把它抽象成一个递推公式,不用想一层层的调用关系,屏蔽掉递归细节,不要试图用人脑去分解递归的每个步骤。
对于递归代码,若试图想清楚整个递和归的过程,实际上是进入了一个思维误区。
那该如何理解递归代码呢?如果一个问题A可以分解为若干个子问题B、C、D,你可以假设子问题B、C、D已经解决。而且,你只需要思考问题A与子问题B、C、D两层之间的关系即可,不需要一层层往下思考子问题与子子问题,子子问题与子子子问题之间的关系。屏蔽掉递归细节,这样子理解起来就简单多了。
因此,理解递归代码,就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解递归的每个步骤。

五、递归常见问题及解决方案

1. 递归代码要警惕堆栈溢出
何避免出现堆栈溢出呢?
可以通过在代码中限制递归调用的最大深度的方式来解决这个问题。


// 全局变量,表示递归的深度。
int depth = 0;int f(int n) {++depth;if (depth > 1000) throw exception;if (n == 1) return 1;return f(n-1) + 1;
}

2. 递归代码要警惕重复计算
为了避免重复计算,我们可以通过一个数据结构(比如散列表)来保存已经求解过的 f(k)。当递归调用到 f(k) 时,先看下是否已经求解过了。如果是,则直接从散列表中取值返回,不需要重复计算,这样就能避免刚讲的问题了。


public int f(int n) {if (n == 1) return 1;if (n == 2) return 2;// hasSolvedList可以理解成一个Map,key是n,value是f(n)if (hasSolvedList.containsKey(n)) {return hasSolvedList.get(n);}int ret = f(n-1) + f(n-2);hasSolvedList.put(n, ret);return ret;
}

六、如何将递归改写为非递归代码?

利是递归代码的表达力很强,写起来非常简洁;而弊就是空间复杂度高、有堆栈溢出的风险、存在重复计算、过多的函数调用会耗时较多等问题。
笼统的讲,所有的递归代码都可以改写为迭代循环的非递归写法。如何做?抽象出递推公式、初始值和边界条件,然后用迭代循环实现。


int f(int n) {if (n == 1) return 1;if (n == 2) return 2;int ret = 0;int pre = 2;int prepre = 1;for (int i = 3; i <= n; ++i) {ret = pre + prepre;prepre = pre;pre = ret;}return ret;
}

七、调试递归方法

  1. 打印日志发现,递归值。
  2. 结合条件断点进行调试。

【进阶修炼】
[递归]一文看懂递归

笔记整理来源: 王争 数据结构与算法之美

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

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

相关文章

二元随机变量函数的分布

在前面的文章记录了二元随机变量的定义、离散型二元随机变量的联合分布律/联合概率密度函数、边际分布律/边际概率密度函数、条件分布律/条件概率密度 &#xff0c;以及对应的 联合分布函数、边际分布函数、条件分布函数。这篇文档介绍二元随机变量函数的分布。 二元随机变量函…

力扣 1553. 吃掉 N 个橘子的最少天数 记忆化DFS|记忆化BFS|剪枝

吃掉 N 个橘子的最少天数 厨房里总共有 n 个橘子&#xff0c;你决定每一天选择如下方式之一吃这些橘子&#xff1a; 吃掉一个橘子。 如果剩余橘子数 n 能被 2 整除&#xff0c;那么你可以吃掉 n/2 个橘子。 如果剩余橘子数 n 能被 3 整除&#xff0c;那么你可以吃掉 2*(n/3) 个…

spring容器bean的作用域 spring容器是否是单例的一些问题

Spring容器中Bean的作用域 当通过Spring容器创建一个Bean实例时&#xff0c;不仅可以完成Bean实例的实例化&#xff0c;还可以为Bean指定特定的作用域。Spring支持如下5种作用域&#xff1a; singleton&#xff1a;单例模式&#xff0c;在整个Spring IoC容器中&#xff0c;使用…

第四十期:2019年度十大Web开发趋势

本文和您一起讨论那些本年度改变软件开发行业、特别是Web开发方面的十大趋势。 如今&#xff0c;随着各种新趋势的层出不穷&#xff0c;Web和移动领域的创新不仅改变了人们、乃至整个社会的日常行为习惯、以及业务处理方式&#xff0c;而且也使得开发人员能够轻松、且高效地创建…

【数据结构与算法】排序 冒泡、插入、选择 O(n^2)

冒泡、插入、选择 O(n2) 基于比较 快排、归并 O(nlogn) 基于比较 计数、基数、桶 O(n) 不基于比较 一、如何分析一个排序算法&#xff1f; 学习排序算法的思路&#xff1f;明确原理、掌握实现以及分析性能。如何分析排序算法性能&#xff1f;从执行效率、内存消耗以及稳定性…

第一单元:微积分

打算写一下微积分的笔记。以供日后复习。学习来源是网易公开课的麻省理工大学的单变量微积分。下载了MIT官网的课堂笔记。 第一单元概览 1 微积分、斜率、速度、和变化率(derivatives,slop,velocity and rate of change) 2 极限、连续性、三角函数的极限(Limits,continuity …

题解 P5301 【[GXOI/GZOI2019]宝牌一大堆】

这道题除了非常恶心以外也没有什么非常让人恶心的地方 当然一定要说有的话还是有的&#xff0c;就是这题和咱 ZJOI 的 mahjong 真的是好像的说~ 于是就想说这道题出题人应该被 锕 掉 noteskey 整体的思路就是特判国士无双和七对子&#xff0c;然后 dp 搞普通的胡牌 dp 状态设计…

力扣:组合总和 II DFS剪枝

组合总和 II 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 说明&#xff1a; 所有数字&#xff08;包括目标数&#xff09;都是正整数。 解集不能包…

[Leetcode][第336题][JAVA][回文对][暴力][HashSet][字典树]

【问题描述】[困难] 【解答思路】 1. 暴力&#xff08;超时&#xff09; 时间复杂度&#xff1a;O(n 2 m)&#xff0c;其中 n 是字符串的数量&#xff0c;m 是字符串的平均长度 空间复杂度&#xff1a;O(1) class Solution {public List<List<Integer>> palindr…

第十二期:面试官问你什么是消息队列?把这篇甩给他!

消息队列不知道大家看到这个词的时候&#xff0c;会不会觉得它是一个比较高端的技术&#xff0c;反正我是觉得它好像是挺牛逼的。 一、什么是消息队列&#xff1f; 消息队列不知道大家看到这个词的时候&#xff0c;会不会觉得它是一个比较高端的技术&#xff0c;反正我是觉得它…

第三章 随机变量的数字特征

数学期望 数学期望用来反映平均情况。 定义 设离散型随机变量X的分布律为P(Xxk)pk,k1,2,3...&#xff0c;若级数∑∞k1xkpk是收敛的&#xff0c;则称级数∑∞k1xkpk的值为随机变量X的数学期望。记为E(X)。E(X)∑k1∞xkpkpk可以理解为加权平均中的权值。数学期望又称为 均值。 …

python二进制、字符编码及文件操作

1. 二进制 bin()十进制转二进制 0b oct&#xff08;&#xff09;十进制转八进制 0o hex&#xff08;&#xff09;十进制转十六进制 0x&#xff0c;4个二进制对应1个16进制&#xff0c;用于网络编程&#xff0c;数据存储 print(int(110111,2)) 55 print(int(ffff,16)) 65535 p…

【数据结构与算法】【字符串匹配】Trie树

单模式串匹配 BF 算法和 RK 算法 BM 算法和 KMP 算法多模式串匹配算法 Trie 树和 AC 自动机 一、 什么是“Trie树”&#xff1f; 1. 他是一种树形结构&#xff0c;是一种专门处理字符串匹配的数据结构&#xff0c;解决在一组字符串集合中快速查找某个字符串的问题。 2. Trie…

第十三期:消灭 Java 代码的“坏味道”

代码中的"坏味道"&#xff0c;如"私欲"如"灰尘"&#xff0c;每天都在增加&#xff0c;一日不去清除&#xff0c;便会越累越多。如果用功去清除这些"坏味道"&#xff0c;不仅能提高自己的编码水平&#xff0c;也能使代码变得"精白…

力扣 两数相加 指针操作注意事项

两数相加 给出两个 非空 的链表用来表示两个非负的整数。其中&#xff0c;它们各自的位数是按照 逆序 的方式存储的&#xff0c;并且它们的每个节点只能存储 一位 数字。 如果&#xff0c;我们将这两个数相加起来&#xff0c;则会返回一个新的链表来表示它们的和。 您可以假设…

[Leetcode][第100题][JAVA][相同的树][二叉树][深度遍历][递归]

【问题描述】[中等] 【解答思路】 深度遍历/递归 终止条件与返回值&#xff1a; 当两棵树的当前节点都为 null 时返回 true 当其中一个为 null 另一个不为 null 时返回 false 当两个都不为空但是值不相等时&#xff0c;返回 false 执行过程&#xff1a;当满足终止条件时进…

Java_多态

定义&#xff1a; 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定&#xff0c;而是在程序运行期间才确定&#xff0c;即一个引用变量到底会指向哪个类的实例对象&#xff0c;该引用变量发出的方法调用到底是哪个类中实现的…

第十四期:5 个 JS 不良编码习惯,你占几个呢?

在阅读JavaScript代码时&#xff0c;你是否有过这种感觉&#xff1a;你几乎不明白代码的作用&#xff1f;代码使用了很多 JavaScript 技巧&#xff1f;命名和编码风格太过随意&#xff1f; 这些都是不良编码习惯的征兆。 在阅读JavaScript代码时&#xff0c;你是否有过这种感觉…

力扣3. 无重复字符的最长子串 two pointer算法|滑动窗口|尺取法

无重复字符的最长子串 给定一个字符串&#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最…

318. Maximum Product of Word Lengths

问题&#xff1a;给定一个字符串数组words&#xff0c;找到这样的最大值&#xff1a;length(word[i]) * length(word[j])&#xff0c;words[i]和words[j]没有共同的字母。假设输入字符串只包含小写字母。如果不存在这样的两个字符串&#xff0c;则返回0。 思路&#xff1a;难点…