一、递归
递归设计经验
- 找重复(子问题)
- 找重复中变化量→参数
- 找参数变化趋势→设计边界
练习策略
- 循环改递归
- 经典递归
- 大量练习,总结规律,掌握套路
- 找到感觉,挑战高难度
二、递归求解
单分支递归
1.使用递归求阶乘
public static int f(int n){ if(n==1){ return 1; } return f*f(n-1); }
- 找重复:n*(n-1)的阶乘,求n-1的阶乘是原问题的重复(规模更小)
- 找变化:变化的量应该作为参数
- 找边界:出口
2.打印i-j
public static void printItoJ(int i,int j){ if(i>j){ return; } System.out.println(i); printItoJ(i+1,j); }
- 找重复:打印i,然后再打印[i+1,j],规模更小
- 找变化:变化的量应该作为参数
- 找边界:出口
3.数组求和
public static int sum(int[] nums,int i){ if(i==nums.length){ return 0; } return nums[i]+sum(nums,i+1); }
4.翻转字符串
public static String reverse(String str,int index){ if(index==0){ return String.valueOf(str.charAt(0)); } return String.valueOf(str.charAt(index))+reverse(str,index-1); }
5.递归求最大公约数(碾转相除法)
public static int gcd(int a,int b){ if(a%b==0){ return b; } return gcd(b,a%b); }
- 递推公式
6.递归来进行插入排序
- 非递归插入排序
public static void insertionSort(int[] nums){ for(int i = 1;i<nums.length;i++){ int temp = nums[i]; int j = i-1; while(j>=0 && temp<nums[j]){ nums[j+1] = nums[j]; j--; } nums[j+1] = temp; } }
- 递归插入排序
public static void insertionSort(int[] nums,int index){ if(index==0){ return; } //对前面的数进行排序 insertionSort(nums,index-1); //将当前数插入有序数组中 int temp = nums[index]; int j = index-1; while(j>=0 && temp<nums[j]){ nums[j+1] = nums[j]; j--; } nums[j+1] = temp; }
多分支递归
1.求斐波那契数列第N项
public static int f(int n){ if(n==1 || n==2){ return 1; } return f(n-1)+f(n-2); }
- 递推公式f(n)=f(n-1)+f(n-2)
其实是先根(先序)遍历递归解答树,如下图所示:
发现有很多重复项,可以优化(以后讲)
递归总结:
找重复
- 找到一种划分方法
- 如果找不到一种划分方法,找到递推公式或者一种等价转化(往往是数学上的)
找变化的量
- 变化的量通常要作为参数
找到出口
- 根据参数变化的趋势,对边界进行处理控制,适时终止递归