🤌具体实现-递归简介
框架:if {return} (base case最简单/基础的情况,可能不止一个); else {return} (recursive case); 递归思想合理性的数学支撑-数学归纳法
递归用于分治--分而治之思想的代码实现之一-->看算法笔记递归部分
递归函数:不需要考虑递归函数是如何实施的,只需要考虑它该做什么!!一般而言题目要求什么就定义它的功能是什么
base case (递归边界):思考角度1.递归到哪种情况下结束,如果一下想不清楚可以从recursive case 往后倒推<-->2.最简单的情况
递归表达式:f(n) = xxxxxxf(n-1)xxxx,也就是需要思考如何构建含有f(n-1)的表达式才能得到f(n);
1.最简单的递归:简单模拟,题目已经给出了递归的边界(base case)和递归表达式(recursive case),按照它写就完了,比如斐波那契。
2.需要稍微思考递归边界(base case)和递归表达式:
递归函数:需要思考用什么(下标/个数/大小。。。)作为它的参数;一般而言题目要求输出的数据是什么类型,递归函数就定义为改类型,也即直接返回要求输出的数据(除了二维递归,它一般用全局数组记录结果,所以二维递归的递归函数一般定义为void)
递归表达式:
子问题(与原问题比:规模更小且具有相同结构): f(n-1)
f(n) = xxxxxxf(n-1)xxxx,也就是需要思考如何构建含有f(n-1)的表达式才能得到f(n);
递归边界:无法再分割的情况
(1)🌰用递归实现返回一个反转字符串:
注意,递归函数reverseStr(int n)的参数n代表的是:字符个数,n个字符


(2)🌰求完全二叉树路径的最大值
晴问算法数塔,设树深度为n

难点:
数据存储:完全二叉树可用正方形数组a[n+1][n+1] (i/j从下标1开始存储)存,用a[i][j](数组的第i行第j列)存储树的第i行第j列数据;第i行只有i个数据;
递归表达式:假设塔顶是a[i][j], 则它的左子树塔顶为a[i+1][j], 右子树塔顶为a[i+1][j+1], 那么从该塔顶到塔底路径的最大值为F( i, j )= a[i][j]. + max( F(i+1, j), F(i+1, j+1) ), 也因此递归函数的参数可用int i, int j;
递归边界:当塔顶是完全二叉树树底其中之一的元素,即i == n时,F[i][j] = a[i][j];
(3)可以考虑两种递归边界的情况
🌰用递归判断回文字符
因为要求判断,所以递归函数的类型可为bool F(. );
难点:
递归边界:两个字符的情况即j == i+1, F(i, j) =. s[i] == s[j];
一个字符的情况即 i== j ,F(i, j) == true;
然后集成:i >= j时,返回true;
递归表达式:递归边界以外的情况,F(i, j) = (s[i] == s[j]) and F(i+1, j-1) ;
🌰上楼梯,最后一次抬脚可上一级/两级台阶,(类汉诺塔问题,解题思路一致,详见cs61a)

递归边界可以集成为if(n <= 1),因为当n==2时,count(2) = count(1) + count(0)
(4) 汉诺塔问题(详见cs61a 递归部分视频)
A柱起始有n个盘,先把上面n-1个盘放到B(辅助柱temp),再把最后一个放到C, 最后把temp柱子的n-1个移到C。(三步)
@要点:2个盘子及以上才需要借助第三方柱子()
@难点:将以上具体的柱子用代数抽象成三个部分,也即char a, char b, char c , 三个抽象的代数。
~递归表达式: H(int n, char a, char b, chat c),
H( n-1, a, c, b )把from上的n-1(当作一个整体)个小盘子,借助c移动到b上;
H.move(1, a c);把a最底下的一个盘子,移动到c,题目要求我们打印出每一步骤:则该句转化的代码是:printf(" ->. ",a, c);
H(n-1, b ,a, c)
~递归边界: n == 1时,不需要借助第三方柱子,直接移动即可。(直接打印printf(" ->. ",from, to);)
c语法:printf("%d\n",(int)pow(2.0, n*1.0)-1 ); #include <cmath>
3.👀需要给递归表达式套上循环的复合处理
(1)🌰自然数分解之最大积

主思想:对自然数 n 的分解,有两“种”分解方案:i+(n-i) 和. i+F(n-i) 。递归的每一步都是把 n 减去某个数 i,然后继续递归分解 n-i。这就相当于在每一步确定了分解中的一个数,然后将剩余的部分继续递归分解。
递归函数:题目要求乘积最大值,那就定义递归函数为int f(int n) 并返回对n分解后的乘积最大值;
递归边界:明显当n == 1时,无法再对1分割,即边界为:if(n == 1) return 1;
递归表达式:如何从f(n-1)构建出表达式等于f(n),有“两种”分解乘积方案: i * (n-i) 和 i* f(n-1), 所以f(n) = max ( i* (n-i), i*f(n-i) ) = i * max( n-i, f(n-i) ).
#include <iostream>
#include <algorithm>
using namespace std;
//递归函数直接返回要输出的数据
int f(int n) {
if(n == 1)
return 1;
else
{
int Current_max = 1;
for(int i = 1; i < n; i++)
Current_max = max(Current_max, i * max(n-i, f(n-i)));
return Current_max;
}
}
int main() {
int n;
scanf("%d", &n);
printf("%d\n", f(n));
return 0;
}
(2)🌰自然数分解之方案数

难点:如何解决重复出现的问题-->限制最大拆分数增加一个参数bound,F(n, bound)
当前自然数 n 的分解问题,递归地减少为分解更小的自然数 n-i 的问题。例如,假设 n=5,选择 i=3,则问题变成了分解 2,递归调用 F(2, 3)。而• bound参数是为了避免出现重复分解。通过限制当前可用的最大值不超过 i,确保每次递归分解方案是非递增顺序的。
bound 参数的作用是在递归调用时,限制下一步递归中允许选择的最大值。
代码具体执行流程图

但又出现了第一“种”分解方案重复的问题,因此也要对它做限制让它递减(i >= n-i ) cnt才能++。注意点:第一种分解方案还要判断n-i > 0,保证n-i是正数
1215

被折叠的 条评论
为什么被折叠?



