递归
什么情况下可以考虑使用递归?
- 大问题可以分解成更小的子问题(递)
- 小问题和大问题求解方式一致,只是数据规模不一样
- 大问题最终可以分解成基本问题,基本问题可以直接求解
- 子问题的解汇集起来可以得到大问题的解(归)
递归两个基本要素
- 边界公式
- 递推公式
总结
核心:分而治之,减小问题规模
⚠️注意:一定要有递归出口
递归的弊端:重复计算(例如在不死神兔问题中)
递归的很多问题也可以转化成循环来做
题目
- 求阶乘
- 不死神兔—斐波那契
- 猴子吃桃
- 求0—7所能组成的奇数个数
- 上楼梯问题
- 直线分割平面问题
- 汉诺塔问题 ----6.16更新~
- 反转单链表
- 一个楼梯有n (n >= 1)级,每次走1级或两级,请问从1级台阶走到第n级台阶一共有多少种走法(假设一开始站在第0级台阶上)
思路:
代码:
public class RecursionStair {
public static void main(String[] args) {
stair(n);
}
//上n阶台阶,返回方法数量
public static int stair(int n){
if(n<1){
return -1;
}
if(n==1){
return 1;
}
if(n==2){
return 2;
}
return stair(n-1)+stair(n-2);
}
}
本题其他做法:
// 当n超过100时,会返回负值, int类型已经不能表示了……
//1.========数组的方法========
public static long stair(int n){
if(n==1) return 1;
if(n==2) return 2;
long[] arr = new long[n];
arr[0]=1;
arr[1]=2;
for (int i = 2; i <n ; i++) {
arr[i] = arr[i-1]+arr[i-2];
}
return arr[n-1];
}
//2.=======动态规划,在力扣上看到大佬做的=====
// 利用一个temp存入 当n-1时的值+当n-2时的值
// = = 用递归的话,重复计算太多,无法通过
public static int solution(int n ){
if(n<=2) return n;
int p =1;
int q =2;
for (int i = 3; i <= n ; i++) {
int temp = p+q;
p = q;
q = temp;
}
return q;
}
- 计算n条直线最多能把平面分成多少部分? n>=1)
这题还可以看一下:折线分割平面
【递推】直线、折线、曲线分割平面、平面分割空间
以下是本人愚钝的思路:
代码:
/**
* 题目:计算n条直线最多能把平面分成多少部分? n>=1
* 题目条件是最多,故n>=2后新加的线必须与原有每条线都相交且交点不能重合
* f(1)=2;
* f(2)=4;
* ...
* f(n)=f(n-1)+(n-1)-1+2
* =f(n-1)+n
* (n-1)-1+2 -> 表示 第n条线加入后被分成(n-1)-1条线段和2条射线->将原有区域一分为二
*/
import java.util.Scanner;
public class PlanePart {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请问您想用几条线将平面分割呢?");
int line = scan.nextInt();
System.out.println("Method 1:");
System.out.println(partNumber(line));
System.out.println("Method 2:");
System.out.println(partNumber1(line));
}
//======数学方法======
// n -> numbers of line
public static int partNumber(int n ){
if(n<1){
return -1;
}
return n*(n+1)/2+1;
}
//===== Recursion =======
public static int partNumber1(int n){
if(n<1){
return -1;
}
if(n==1){
return 2;
}
return partNumber1(n-1)+n;
}
}
- 汉诺塔问题
有很多文章介绍了……递归的经典题!
hhh 很多人都说不要去管递归的一步一步具体是怎么实现的,要抓住核心! 减小问题规模!
关于这个题,我觉得……其实去玩一玩汉诺塔游戏真的可以帮助理解一下……
= = 我就是玩了大概一小时,然后可以稍稍体会到:先把n-1个盘子挪到辅助杆 -> 把第n个(即最底部的)盘子挪到目标杆 -> 把n-1个盘子挪到目标杆 | 这么一个过程……当你完成第一步后,其实最初最底下的盘子当作消失了,重新定义哪个是“起始、辅助、目标”,然后n-1个盘子只是重复第一步过程……
public class HanoiProblem {
public static void main(String[] args) {
hanoi('A','C','B',3);
}
//start 起始杆名称
//end 目标杆名称
//middle 辅助杆名称
// n 盘子数量
// = = 注意变量名的顺序,起始、目标、辅助
public static void hanoi(char start, char end ,char middle, int n){
if(n==1){
System.out.println(start+"-->"+end);
return;
}
// first step 把n-1个盘子从start杆挪到 middle杆
hanoi(start,middle,end,n-1);
//最底部的n从start杆挪到end杆
System.out.println(start+"-->"+end);
//最后middle杆为起始,end依然是目标,但此时start成为了辅助杆
hanoi(middle,end,start,n-1);
}
}
结果:
A–>C
A–>B
C–>B
A–>C
B–>A
B–>C
A–>C
- 反转单链表(待更新)