算法2. 分治入门(采用递归实现)

 🤌具体实现-递归简介

框架: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个字符

129b36fb60e7851aed705b2162b878d2.png

1d2e0244be5ea2eb92d12f02e13d9c6b.png

(2)🌰求完全二叉树路径的最大值

晴问算法数塔,设树深度为n

511a273868e98b95f1bd2d51075b7f91.png

难点:

  数据存储:完全二叉树可用正方形数组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)

8d5011ab9ff4e89cbae8ceb935468b91.png

递归边界可以集成为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)🌰自然数分解之最大积

2b8c16a2892b6d8bc237c34234de8f93.png

主思想:对自然数 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)🌰自然数分解之方案数

a1b4236ff45024d0b3bfa28e6e16c857.png

难点:如何解决重复出现的问题-->限制最大拆分数增加一个参数bound,F(n, bound)

当前自然数 n 的分解问题,递归地减少为分解更小的自然数 n-i 的问题。例如,假设 n=5,选择 i=3,则问题变成了分解 2,递归调用 F(2, 3)。而• bound参数是为了避免出现重复分解。通过限制当前可用的最大值不超过 i,确保每次递归分解方案是非递增顺序的。

bound 参数的作用是在递归调用时,限制下一步递归中允许选择的最大值。

 代码具体执行流程图

b53e101e12ba4982bd066eae1ebb8dfd.jpeg

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值