递归算法总结
设计的方案:
1、找重复(子问题) 2、找重复中的变化量---->参数 3、找参数变化趋势---->设计出口
练习策略:
1、循环改递归 2、多刷一些经典的递归题目3、大量练习,总结规律,掌握套路4、找到感觉,挑战高难度
递归的一个基本形式就是栈的调用,前进后出, 自身调用自身,但要注意死循环的问题。因此,在设计递归的时候,要有限制,注意边界的设计以及出口的设计。不然的话,无限循环溢出。
类型一:一刀切
这一部分的题目都是基于一种贴蛋糕的思想进行解题,即每次划分一个子模块,让子模块来代替主模块进行完成相应的部分,然后加在一起的和就是整个模块。本质上都是可以找到一个递推的关系,递推的公式从而进行一个设计。但这里需要注意的就是,子模块要跟主模块一样,执行的内容都是一样的,比如下图,子模块都是完成其中的某部分,切掉以后,然后移动到下面给下一个子模块来帮自己进行完成。得到最后一个临界结果以后,需要返回告诉自己上一个模块,我帮你完成了你这部分的内容,结果是什么什么,然后每一层每一层进行一个反馈,从而让每个子模块对应的主体获取相应的数据,从而使得最终的整体需求完成(表述有些奇怪,可以看图)。相当于:我们自己只用做一部分,剩下的就委派给别人,由下一个人进行处理,两者合起来是整一部分的,但我们自己这一块就小一些
但这里需要注意的是, 必须要有临界就是迭代的终点,不然就会栈溢出。一共是三步走:找重复、找变化、找边界
第一题 求n的阶乘
分析:f1(n):求n的阶乘----->f1(n-1)求n-1的阶乘
1、找重复: n*(n-1)的阶乘,求n-1的阶乘是原问题的重复(规模更小)----->子问题
2、找变化: 将变化的量应该作为参数。在这里就是n的变化,在越来越变的小了,因此变化的量就作为参数
3、找边界: 根据变化的趋势,去找到相对应的边界。为了避免死循环的问题,应该设置边界,有一个限制,不然就会陷入死循环,即出口,即n小到什么程度
public static int f1(int n){
if(n==1){
return 1;
}
return n*f1(n-1);
}
第二题 打印i~j
分析:[这里肯定是i<j]
1、找重复:i+1
2、找变化:变化的量作为参数
3、找边界:出口
public static void f2(int i, int j){
System.out.println(i);
if(i==j)//找到的边界,即从i走到了j以后,就是终止了
return;
f2(i+1,j);
}
第三题 arr数组的求和
分析:
1、找重复:arr的数组下标在不断的变化,在不断的推进
2、找变化:变化的量作为参数
3、找边界:begin==arr.length-1的时候,作为这个循化的边界
public static int f3(int[] arr,int begin){
if(begin==arr.length-1)
return arr[begin];
return arr[begin]+f3(arr