递归整理及几个经典题目
什么是递归
百度百科:程序调用自身的编程技巧称为递归( recursion)。
借用知乎上Memoria的回答:
假设你在一个电影院,你想知道自己坐在哪一排,但是前面人很多,你懒得去数了,于是你问前一排的人「你坐在哪一排?」,这样前面的人 (代号 A) 回答你以后,你就知道自己在哪一排了——只要把 A 的答案加一,就是自己所在的排了。不料 A 比你还懒,他也不想数,于是他也问他前面的人 B「你坐在哪一排?」,这样 A 可以用和你一模一样的步骤知道自己所在的排。然后 B 也如法炮制。直到他们这一串人问到了最前面的一排,第一排的人告诉问问题的人「我在第一排」。最后大家就都知道自己在哪一排了。
递归问题分析的核心
一个合法的递归定义包含两个部分:基础情况和递归部分。
分析一个递归问题就是列出递归定义表达式的过程。
上面那个电影院排数的问题表达式可以列为:
f(n) =\begin{cases}1, & \text{n= 1} \\f(n-1)+1, & \text{n>1}\end{cases}
几个经典题目
斐波那契数列
斐波那契数列的排列是:0,1,1,2,3,5,8,13,21,34,55,89,144……依次类推下去,你会发现,它后一个数等于前面两个数的和。在这个数列中的数字,就被称为斐波那契数。
递归思想:一个数等于前两个数的和。(这并不是废话,这是执行思路)
首先分析数列的递归表达式:
f(n) =\begin{cases}n, & \text{n1}\end{cases}
代码如下:
/*** 斐波那契数列的递归写法* 核心:一个小的解决终点,然后大的问题可以循环在小问题上解决* @param n* @return*/
long F(int n){if (n<=1) return n;return F(n-1)+F(n-2);
}/*** 斐波那契数列的递推写法* @param n* @return*/
long F1(int n){if (n<=1) return n;long fn = 0;long fn_1 = 1;long fn_2 = 0;for (int i = 2; i <= n; i++) {fn = fn_1 + fn_2;fn_2 = fn_1;fn_1 = fn;}return fn;
}
可以看到,递归写法简单优美,省去考虑很多边界条件的时间。当然,递归算法会保存很多的临时数据,类似于堆栈的过程,如果栈深太深,就会造成内存用尽,程序崩溃的现象。Java为每个线程分配了栈大小,如果栈大小溢出,就会报错,这时候还是选择递推好一点。
观察下面的执行过程也会发现,本程序并没有保存每次的运算结果,第三行的F(7)就执行了两次,下层的F(1),F(2)的次数更是指数级增长。这也是本程序的一个弊端。
斐波那契执行过程:
阶乘
递归思想:n! = n * (n-1)! (直接看公式吧)
首先分析数列的递归表达式:
f(n) =\begin{cases}1, & \text{n1}\end{cases}
代码如下:
long factorial(int n){if (n <=1) return 1;return j(n-1)*n;
}
执行过程如下:
倒序输出一个正整数
例如给出正整数 n=12345,希望以各位数的逆序形式输出,即输出54321。
递归思想:首先输出这个数的个位数,然后再输出前面数字的个位数,直到之前没数字。
首先分析数列的递归表达式:
f(n) =\begin{cases}print(n\%10), & \text{n=10}\end{cases}
代码如下:
/*** 倒序输出正整数的各位数* @param n*/
void printDigit(int n){System.out.print(n%10);if (n > 10){printDigit(n/10);}
}
汉诺塔
超经典了的递归解决问题了:
法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
数学描述就是:
有三根杆子X,Y,Z。X杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至Y杆:
1. 每次只能移动一个圆盘;
2. 大盘不能叠在小盘上面。
递归思想:
1. 将X杆上的n-1个圆盘都移到空闲的Z杆上,并且满足上面的所有条件
2. 将X杆上的第n个圆盘移到Y上
3. 剩下问题就是将Z杆上的n-1个圆盘移动到Y上了
公式描述有点麻烦,用语言描述下吧:
1. 以Y杆为中介,将前n-1个圆盘从X杆挪到Z杆上(本身就是一个n-1的汉诺塔问题了!)
2. 将第n个圆盘移动到Y杆上
3. 以X杆为中介,将Z杆上的n-1个圆盘移到Y杆上(本身就是一个n-1的汉诺塔问题了!)
代码如下:
/*** 汉诺塔* 有柱子 x z y,最终将x上的n个圆盘借助z移动到y上* 递归思想:* 1.将x上的n-1个放入到z上,借助y* 2.将x上的n圆盘放到y上* 3.将z上的n-1个圆盘放入y* @param n* @param from* @param tmp* @param to*/
void hanoi(int n,char from,char tmp,char to){if (n>0) {hanoi(n - 1, from, to, tmp);System.out.println("take " + n + " from " + from + " to " + to);hanoi(n - 1, tmp, from, to);}
}
执行过程:
如果一秒钟移动一次,世界毁灭需要多长时间呢?5845.54亿年以上,而地球存在至今不过45亿年,地球现在还是很安全的。
排列问题
输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。
递归思想:
假如针对abc的排列,可以分成 (1)以a开头,加上bc的排列 (2)以b开头,加上ac的排列 (3)以c开头,加上ab的排列
/*** 产生排列组合的递归写法* @param t 数组* @param k 起始排列值* @param n 数组长度*/
void pai(int[] t, int k, int n){if (k == n-1){//输出这个排列for (int i = 0; i < n; i++) {System.out.print(t[i] + " ");}System.out.println();}else {for (int i = k; i < n; i++) {int tmp = t[i]; t[i] = t[k]; t[k] = tmp;//一次挑选n个字母中的一个,和前位置替换pai(t, k+1, n); //再对其余的n-1个字母一次挑选tmp = t[i]; t[i] = t[k]; t[k] = tmp; //再换回来}}
}
本题用递归算法很巧妙,省去了用普通方法时保存数据状态的繁琐操作!
递归整理及几个经典题目相关推荐
- 动态规划经典题目整理
动态规划经典题目整理 背包问题 最长公共子串问题 连续数组最大和问题 持续增加中.... 背包问题 复杂度 O(nW)O(nW)O(nW) nnn为物品种类,WWW是背包的重量 目的:使得背包中的物品 ...
- 十个利用矩阵乘法解决的经典题目
出自matrix67.com 好像目前还没有这方面题目的总结.这几天连续看到四个问这类题目的人,今天在这里简单写一下.这里我们不介绍其它有关矩阵的知识,只介绍矩阵乘法和相关性质. 不要以为数学 ...
- 【转】矩阵十大经典题目
经典题目1 给定n个点,m个操作,构造O(m+n)的算法输出m个操作后各点的位置.操作有平移.缩放.翻转和旋转 这里的操作是对所有点同时进行的.其中翻转是以坐标轴为对称轴进行翻转(两种情况), ...
- 十个利用矩阵解决的经典题目
借鉴做题: 经典题目1 给定n个点,m个操作,构造O(m+n)的算法输出m个操作后各点的位置.操作有平移.缩放.翻转和旋转 这里的操作是对所有点同时进行的.其中翻转是以坐标轴为对称轴进行翻转( ...
- C语言经典题目(一)
分享之前和大家分享一本书叫做<厚黑学>,这本书可以了解一下社会现实,但是看这本书的时候切记,不可迷失自己.扉页的第一段话和大家分享一下:我自读书识字以来,就想为英雄豪杰,求之四书五经,茫无 ...
- 分治法的思想与经典题目
目录 分治法简介 分治法主定理 分治算法的时间复杂度 分治法的基本步骤 分治法的使用条件 分治法的经典题目 50. Pow(x, n) 53. 最大子序和 169. 多数元素 分治法简介 分治法,即& ...
- 算法提高:贪心策略的11个经典题目
目录 字典序最小 零钱问题 股票问题(最多持有一支,可以买卖无限次) 小船过河 任务调度器 摆动序列 最小区间 跳跃游戏 II 分糖果 通配符匹配 拼接最大数 字典序最小 题目 给定一个由字符串组成的 ...
- Leetcode回溯算法经典题目总结
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就 "回溯" 返回,尝试别的路径.回溯法是一种选优搜索法,按选优条件向前搜索 ...
- 动态规划:经典题目汇总
动态规划:经典题目汇总 文章目录 动态规划:经典题目汇总 一.动态规划的定义 二.经典例题 3.1 一维的DP:斐波那契数列.[使用最小花费爬楼梯](https://leetcode-cn.com/p ...
最新文章
- 不投降就是成功 --- 我看《新喜剧之王》
- prometheus变量_Prometheus 数据可视化
- for vue 一行2列_JAVA基础练习试题(2)蓝桥杯 附源代码
- 分享PWM输入模式捕捉4路PWM波形的周期和占空比
- IDEA 点击进入方法内部_一份最详细的 IDEA调试教程,让bug无处藏身!
- va_start(),va_end()函数应用
- centos 网络自动连接_自动连接最优信号 腾讯云?云兔解决物联网络连接问题
- 删除倾斜OSGB数据中的漂浮物
- 车票预订系统 搭建服务器,火车票网上订票系统的设计与实现.doc
- 步态识别技术与ReID技术
- 百度、高德地图数据源是哪里?
- 资产证券化ABS+区块链
- C语言--tips1
- 3G上网本搭建无线路由供iPad上网
- go mod init错误(go: cannot determine module path for source directory)
- VLD的安装使用及其问题
- 快速傅里叶变换FFT C语言实现 可用于嵌入式系统进行模拟采样频谱分析
- 【扫盲系列】分布式+Zookeeper+Docker+K8S
- 有限差分法、一阶向前差分、一阶向后差分
- 关于scanf与scanf_s
热门文章
- 隔离型串口服务器和西门子1500PLC和通讯案例
- 定时器的使用/清除,关闭页面的清除
- adcclk最大_ADC12采样保持时间与采样频率
- 7-89 平原作战 7-79 烟囱的高度(有关正反三角函数·度·分·秒)
- 大佬,IntelliJ IDEA里这种文件是怎么创建的?
- 单机网页游戏的如何修改服务器数据库,三国志单机页游网页版一键端+教程及修改工具...
- 双11女装数据大曝光!淘品牌大势已去
- PAT 1074 Reversing Linked List——双端队列解法
- 软件工程直招士官生_国家鼓励大学生直招士官入伍,主要有4方面考虑,一般人真不知道...
- Android实现八大行星绕太阳3D旋转效果