递归的实质:栈 + 拆解任务
先进后出
如:
这样的函数 , 执行顺序是 f(10) -> f(9) -> f(8)....
但是最后收到结果的却是f(10),因为f(10)要等待f(9)
解决 f(10) 就拆解为解决 f(9)
重点:重复中找变化,变化中找重复
基本形式一: x + 拆解任务 (直接量 + 小规模)
题1:求阶乘
3!= 3 * 2 * 1
= 3 * f() , f() = 2 * 1
= 3 * 2 * f() , f() = 1
if (num == 1){
return 1;
}
核心就是 retrun num * f(num - 1)
题2:翻转字符串
将字符串 "abcd" -> "dcba"
记住递归就是栈
如果一个一个压入"abcd"中的字符,那么出栈顺序就是"dcba"
那么只需要从末尾开始结算即可
if (num == 0) {
return "" + str.chatAt(num)
}// 意味着读到‘a’了
return "" + f(str,num-1)
基本形式二:(小规模 + 小规模)
题3:斐波那契数列
从第三项开始,每一项是前两项之和
1 1 2 3 5 8 13
也就是说求第n项需要知道第 n - 1 和 n - 2 项,第1项和第二项是特殊值
public static int f(int n){ if (n == 1 || n == 2){ return 1; } return f(n-1) + f(n-2); }
题4:最大公约数
辗转相除法:有数m和n , 若 m % n == 0 则 n就是m 和 n 的最大公约数
若 m % n = k, 则令 m = n ,n = k 继续求模 直至为0
public static int f(int m , int n){ int k = m % n; if (k == 0){ return n; } return f (n,k); }
本质就是分解为小规模问题,若当前无法求得公约数,说明当前问题是复杂问题,则转化为小规模。
类型三(无递推公式的小规模问题)
题5:插入排序的递归法
本质问题:对数组进行排序
等价说明:对数组的0-k数排序 + 将插入数插入至有序数组中
public static void f(int[] arr , int k){ if (k == 0){ return; } //对前k-1个数进行排序 f(arr,k-1); //将插入数插入排序数组中 int x = arr[k]; // 取出第k个数 int index = k - 1; // 取得第k-1个数的下标 while(index > -1 && x < arr[index]){ // 检查第k个数与k-1、k-2。。 之间的关系 arr[index + 1] = arr[index]; // 如果第k个数比第k-1、k-2.。个数小,【则将数第k-1个赋值到第k个数上】 index--; } arr[index + 1] = x; }