递归是一种重要的算法,在一些竞赛中,很多问题如果没有特别好的想法时,都可以用递归来求解。
所谓递归,它是指一个函数直接或间接地调用自身来解决问题。递归的基本思想是将一个复杂的问题分解为若干个简单的子问题,然后逐个解决这些子问题,最终达到解决整个问题的目的。
通俗点来讲呢,比如说刚开学,你不知道校长在哪,就去问另一个同学,他也不知道,他就再去问另一个同学,就这样一直循环,终于有个同学知道,他就把答案告诉上一个同学,最终,这个答案顺着这个链条给到了你。
大概就是这么个意思,每一层递归都是带着问题去找答案,而原始答案就是递归的出口,在实际的问题中需要去找到每一层之间的规律,将原始答案通过规律,一步一步计算,最终得到所要的值。
通过递归来做题,最关键的就是找出子问题,找出递归的出口,递归一定是要有出口的,不然函数一直在调用,就会导致内存溢出。
我们还是先通过简单的例题来理解具体的思路:
这里呢,我们需要去求1~100之间的和,那么就可以逐步的去转化为求 1 ~ 99之间的和,1 ~ 98……1 ~ 2 ,以及为1的时候的情况,也就是递归的出口。
//使用递归的方法求1~100的和
public static int getsum(int number) {
if (number == 1) {
return 1;
}
//当前数字加上前面 number - 1 个数字的和
return number + getsum(number - 1);
}
明白了这道题之后,那么通过递归求阶乘也是一样的道理了,我们用代码实现以下:
public static int getFactorialRecursion(int number) {
if (number == 1) {
return 1;
}
//转化为当前数字乘以前 number - 1 的数字的阶乘
return number * getFactorialRecursion(number - 1);
}
方法名起这么长只是为了高级,哈哈哈
接下来我们来看一个很经典的问题——斐波那契数列
我们都知道,斐波那契数列就是第n项等于前两项的和,通项公式也就是
f (n) = f (n - 1) + f (n - 2)
知道这个就好办了,接下来我们看怎么去用递归去求解
public static int fibonacci(int n) {
//第一项和第二项都是 1
if (n == 1 || n == 2) {
return 1;
}
//求第 n 项就是求 第(n-1)和第(n-2)项的和
else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
之前的一篇文章中有关于斐波那契数列的两种解决方式,感兴趣的话可以看一下 : 通过递归和迭代两种方式实现斐波那契数列 。
接下来我们讲一下汉诺塔的问题,每次只能移动一个盘子,而且必须保证大的盘子在小的盘子下面,将初始状态下的 A 柱上的盘子都移动到 C 盘
当 n 为 1的时候,没什么好说的,直接放就完事了
盘子的数量大于 1 时,把除了最下面的盘子看作一个整体,以 C 为辅助塔,移动到目标塔 B ,再将蓝色的盘子放入C,此时最大的蓝色盘子正确归位,每次放置时,这三个柱子谁是开始塔,目标塔,辅助塔都是在不断变化的,这个需要仔细去思考明白。
最后呢将B柱看作一个整体,借助 A 柱,将 B 柱上的盘子放到 C 柱。
完整的代码就是:
public class HanoiTower {
public static void main(String[] args) {
printHanoiTower(3,"A","B","C");
}
//frome:起始塔 temp: 辅助塔 goal: 目标塔
public static void printHanoiTower(int N,String from,String temp,String goal){
if(N == 1){
System.out.println("移动" + N + "从" + from + "到" + goal);
return;
}else{
//转化为从N - 1整体开始移动,此时goal为辅助塔,temp为目标塔对应上面图片的 A, B, C
printHanoiTower(N - 1,from,goal,temp);
//N可以到达目标柱子
System.out.println("移动" + N + "从" + from + "到" + goal);
//N-1整体所在的其实位置是原来的temp塔,以from为辅助塔,移动到目标塔
printHanoiTower(N - 1,temp,from,goal);
}
}
}
运行结果呢也和实际操作一致
递归的代码其实都比较简洁,但其中的思维还是有点难的,我自己学习这个汉诺塔的问题时看了好几个博主的视频才整明白,用动画的话比较直观一点。
最后呢再来一道小白上楼梯的题
没想到吧,这也可以用递归来解决,如果不用递归的话,其实我也想不到该去怎么去做,那接下来我们分析一下这道题:
首先我们假设有 n 级台阶,当他到达n阶之前的一步,可以在第 n - 1级,可以在第 n - 2级,也可以在第 n - 3 级台阶,那么到达第n级台阶的步数就是 f (n - 1) + f( n - 2) + f(n - 3) 加起来
public static int count(int n) {
if (n == 0) {
return 0;
}
if (n == 1) {
return 1;
}
//可以一级一级,也可以两级一起
if (n == 2) {
return 2;
}
//如图,
if (n == 3) {
return 4;
}
return count(n - 1) + count(n - 2) + count(n - 3);
}
n = 3时的情况,共有四种方式
画工不太好,大家凑合着看哈~
那么本次关于递归的分享就到这里了。