文章目录
方法递归
方法递归就是在一个方法执行的内部,自己调用自己的过程,称之为递归
递归分为两个子过程
递过程:函数不断调用自身的过程,直到走到函数的终止条件,第一阶段结束
归过程:函数不断返回的过程称为归过程
程序能够实现方法递归的原因:当在程序中调用另一个函数时,当前程序会暂缓执行,直到调用结束,程序才会继续执行。
如何写出递归代码?
在写递归函数过程中,不要纠结这个函数的内部如何实现,而要注意这个方法的语义(这个函数到底有什么功能),假设这个代码已经由别人写好了,只需要调用这个方法就可以了
求一个整数n的阶乘
这个问题能够拆分成若干个子问题,假设求4!
4!=4 * 3!=4 3 * 2!=4*3 * 2 * 1!
拆分到1就结束了
求n的阶乘
public static int factor(int n) {
if(n==1) { //终止条件
return 1;
}
return n*factor(n-1);//当num>=2时,调用factor(num-1)帮我求出num-1的阶乘
}
public static void main(String[] args) {
System.out.println(factor(5));
}
传入一个num的值,求出1+2+3+…+num的和
这个问题的终止条件仍然是num=1;
public static void main(String[] args) {
System.out.println(sum(5));
}
public static int sum(int num) {
if(num==1) {//终止条件
return 1;
}
return num+sum(num-1);//当num>=2时,调用sum(num-1)求出num-1+...+1的和
}
写出一个方法,这个方法输入一个非负整数,返回组成这个数的组成之和
public static void main(String[] args) {
System.out.println(add(1234));
}
public static int add(int n) {
if (n<10) {//终止条件
return n;
}
return n%10+add(n/10);//当n>=10时
}
递归函数的关键
方法调用时,程序会卡在方法的调用区,直到方法返回继续执行
斐波那契数列指的是这样一个数列:1,1,2,3,5,8,13,21,34,55,89…
这个数列从第3项开始,每一项都等于前两项之和。
传入任意的正整数n,求出其对应的斐波那契函数
public static int fibonacci(int n) {
if (n==1||n==2) {//终止条件
return 1;
}
return fibonacci(n-1)+fibonacci(n-2);//当n>2时每一项的都等于前两项之和
}
public static void main(String[] args) {
System.out.println(fibonacci(3));
}
递归的优化思路一般有两种思路
1.记忆化搜索/剪枝 已经被计算过的数字我就不再重复计算,可利用Map集合
2.dp 动态规划 自底向上解决问题
斐波那契函数的优化
public static int fibo(int num) {
int num1 = 1;
int num2 = 1;
for (int i = 3; i <=num ; i++) {
int num3 = num1+num2;
num1=num2;
num2=num3;
}
return num2;
}
相关习题
传入任意一个正整数,按顺序输出每一位
public static void printArr(int n) {
if(n<10) {//终止条件
System.out.println(n);
return;
}
printArr(n/10);//还有高位不能简单输出
System.out.println(n%10);//高位已经找到
}
public static void main(String[] args) {
printArr(1234);
}
青蛙跳台阶
一只青蛙一次只能跳一级或者二级台阶,求若台阶为n,青蛙有几种跳法?
青蛙跳台阶类似于斐波那契函数,除了前两阶台阶,跳的台阶数n等于前两个台阶的跳法之和
假设要跳到第五级,第一次只可能有两种跳法,跳一级或者跳两级,跳完一级后还有四级,跳完两级后还有三级,把三阶的跳法加上四阶的跳法就等于第五阶的跳法
public static int jumpFloor(int n) {
if (n==1||n==2) {//终止条件
return n;
}
return jumpFloor(n-1)+jumpFloor(n-2);//当n>3时需要调用前两项之和
}
public static void main(String[] args) {
System.out.println(jumpFloor(5));
}
汉诺塔
汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。
大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。
大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。
并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。
求汉诺塔问题
当只有一个盘子时只需要将A移动到C即可
出现两个盘子时需要将盘子1先移动到B
再将盘子2移动到C
最后把盘子1从B移动到C即可
出现三个盘子时需要先将盘子三上面的盘子通过C移动到B
再将盘子3从A移动到C
再将B中的盘子通过A移动到C
四个盘子也是先将盘子4上面所有的盘子通过C移动到B
再将盘子4移动到C
最后B上的三个盘子通过A移动到C上
下列演示一下有六个盘子的情况
从上面几次可以总结出下列规律
1.盘子只有一个时只需要将盘子1从盘子A移动到C
2.如果有盘子数大于1,需要将盘子n上所有的盘子通过C移动到B,再将盘子n从A移动到C,最后将在B上的盘子数n-1从A移动到C
public static void hanoiTower(int disks,char A,char B,char C) {//disks表示盘子的编号,A,B,C表示A,B,C三塔
if (disks==1) {
move(1, A, C);//盘子只有一个时只需要将盘子1从盘子A移动到C
return;
}
hanoiTower(disks-1,A,C,B);//如果有盘子数大于1,需要将盘子n上所有的盘子通过C移动到B
move(disks,A,C);//将盘子n从A移动到C
hanoiTower(disks-1,B,A,C);//2.最后将在B上的盘子数n-1从A移动到C
}
public static void move(int disks,char A,char B) {//移动盘子的方式,盘子disks从哪个塔移动到哪个塔
System.out.println("第"+disks+"个盘子,"+A+"->"+B);
}
public static void main(String[] args) {
hanoiTower(3,'A','B','C');
}