首页 > 其他分享 >递归 | 分治

递归 | 分治

时间:2024-07-08 15:57:08浏览次数:10  
标签:return 递归 递归函数 int 分治 递推 sf

这两个算法有部分重合,所以一起讲。

递归 \(\sf\small\color{gray}Recursion\)

递归是递归函数的灵活运用。
说到底,它是一个 \(\color{blue}\texttt{C++}\) 的一个语言特性。
在函数内部调用函数,会使得思路更加清晰明了。

观察生活,很多事情随着规模或阶段的上升而变得越来越复杂。
然而,此规模或阶段往往又和前面的规模或阶段有着联系。
找出这个联系并解决问题的算法就叫递推。

这是我在 递推 | 差分与前缀和 里写过的一句话。
找出了关系,使用数组迭代,是递归。找出了关系,用递归函数迭代,就是递归。
递归的板子不是死的。它很活,视具体递推(归)式而变。

递归函数

int f(int a)
{
	return f(a);
}

这严格来说不算一个递归函数。它永远调用自己,造成 \(\sf\color{red}死递归\) 。

int f(int a)
{
	return f(a-1);
}

这样呢?
的确不是重复调用自己,可是 a 可以无限小下去,依然是死递归。
怎么办呢?

int f(int a)
{
	if(a==1)	return 1;
	return a+f(a-1);
}

这样呢?
只要 a 是大于一的,那么这个函数就不会死。

递归函数三要素

\(\boxed{\sf调用自身}\boxed{\sf状态转移}\boxed{\sf递归边界}\)
此三者缺一不可,不然函数将失去意义。

运用递归函数

这里举一些例子,方便理解。

阶乘

使用递归函数求 \(\sf n!\) 的值。
此题用循环将非常简单。可是用递归函数呢?
调用自身是当然的。
我们按照递推的思想,把定义拆开:

\[\begin{aligned} \sf n!&\sf =n\times(n-1)\times(n-2)\times...\times 3\times 2\times 1 \\ \sf &\sf =n\times(n-1)! \end{aligned} \]

边界呢?
自然是 \(1!=1\) 啦!
至此,思路已经非常清晰了。上代码!

int factorial(int a)
{
	if(a==1)	return 1;
	return a*factorial(a-1);
}

斐波那契数

1 1 2 3 5 8 ...

我们在 递推 | 差分与前缀和 已经推过它的递推式了:

\[\sf F(i)= \begin{cases} \sf F(i-1)+F(i-2)&\sf(i>2)\\ \sf 1&\sf(i=1or2) \end{cases} \]

现在我们用递归实现。

int fibonacci(int a)
{
	if(a==1)	return 1;
	if(a==2)	return 2;
	return fibonacci(a-1)*fibonacci(a-2);
}

至此,有一个小问题暴露了:
F(n) 已经调用过 F(n-1)F(n-2) 了,F(n-1) 又调用了 F(n-2) ,不就浪费资源了吗?
既然已经调用过,那我把它记住不就好了?

斐波那契数 - 记忆化搜索

每一次调用都看看有没有算过,如果算过,就直接拿出来用,没有就记住他。

int Ans[1000]; 
int fibonacci(int a)
{
	if(Ans[a]!=0)	return Ans[a];
	if(a==1)	return 1;
	if(a==2)	return 2;
	Ans[a]=fibonacci(a-1)*fibonacci(a-2);
	return Ans[a];
}

算法优劣

递归肯定是没有递推优的。每一次调用函数都会新开空间,进入与返回也会花时间,递归层数一多,栈空间还可能炸。
那为什么还用递归?
如果你不知道递推层数,你怎么知道你要什么时候停下来?
而递归 if 里的东西什么都可以。
况且递归思维难度小啊。

分治 \(\sf\small\color{gray}Partition\)

分治分治,分而治之。

字面意思,把一个问题分成两个,三个甚至多个问题。
其实分治可以想递推一样,用循环解决,二分就是一种这样的例子。
还有的,就用递归函数解决吧。

运用

快速模

int FastMod(int a,int b,int k)
{
	if(b==1)return a%k;
	const int o=FastMod(a,b/2,k)%k;
	if(b%2) return (a%k*o%k*o%k)%k;
	else    return (o%k*o%k)%k;
}

此处使用了 % 的性质,不熟悉的同学可以去学学 % 的性质。

区别

我认为吧,分治和递归的本质区别是,一个是由小一点的规模迭代而来,一个是由一半的,三分之一甚至四分之一的相同子问题迭代而来。


完结散花qwq

标签:return,递归,递归函数,int,分治,递推,sf
From: https://www.cnblogs.com/PCwqyy/p/18290078/Recursion-Partition

相关文章

  • 算法力扣刷题 三十五【二叉树基础和递归遍历】
    前言进入二叉树学习。继续。一、二叉树基础理论理论篇——参考链接以下是大纲:二、遍历方式学习递归法实现前、中、后遍历方法。“输入”阶段此处用了第一次递归法实现根据题目的双指针操作,传递递归的参数。解释递归(1)递归:自己调用自己。重复执行一段代码,但是......
  • 代码4:非递归的汉诺塔
    Intro:绪论2:应用视角的操作系统。目的:改写为非递归的汉诺塔,理解“状态机模型”。一、递归版汉诺塔课本上最基础的做法,递归是模拟某一步:把n-1个盘子从from移到via,就能把剩下的一个盘子从from移到to,最后把n-1个盘子从via移到to即可。voidhanoi_r(intn,charfrom,charto,......
  • DCS292 编译器构造实验,手工编写递归下降预测分析程序(2.3)
    help-assignment2.4实验四、手工编写递归下降预测分析程序实验四要求你利用Java语言手工编写一个Oberon-0语言的语法分析程序,该语法分析程序执行与实验三自动生成的语法分析程序类似的功能,但实验三要求逆向工程工具生成的是调用图,而实验四要求生成的是流程图(Flowch......
  • 代码随想录算法训练营第十四天| 226.翻转二叉树 、101. 对称二叉树、104.二叉树的最大
    二叉树学习2226题翻转二叉树,改一下前序递归遍历,每次遍历的时候都调换一下左右结点即可。classSolution{public:voidpreorder(TreeNode*root){if(root==nullptr){return;}TreeNode*tmp;tmp=root->left;......
  • 算法:递归数组求和
    递归数组求和给定一个数组,求所有元素的和算法思想:传入数组和下标,如果下标越界就返回0,否则返回当前值和下一个值的和,递归操作。Java实现:publicclassMain{ publicstaticintfunc(int[]array,intindex){ if(index>array.length-1){ return0; }el......
  • 测量并打印出被装饰函数的执行时间,优化递归函数
    定义了一个装饰器timer,它测量并打印出被装饰函数的执行时间。这个装饰器使用了Python的time模块来记录函数开始和结束的时间点,然后计算并输出函数的运行时长。使用@timer语法将这个装饰器应用到了fibonacci函数上,这是一个递归实现的斐波那契数列计算函数。当调用fibonacci(10)......
  • 读人工智能全传03分治策略
    1. 黄金年代1.1. 图灵在他发表的论文《计算机器与智能》中介绍了图灵测试,为人工智能学科迈出第一步做出了重大贡献1.2. 美国在第二次世界大战后几十年里计算机技术发展的特色,也是美国在未来60年内确立人工智能领域国际领先地位的核心1.3. 1955年,麦卡锡向洛克菲勒研究所撰......
  • 【数据结构】(C语言):二叉搜索树(不使用递归)
    二叉搜索树:非线性的,树是层级结构。基本单位是节点,每个节点最多2个子节点。有序。每个节点,其左子节点都比它小,其右子节点都比它大。每个子树都是一个二叉搜索树。每个节点及其所有子节点形成子树。可以是空树。C语言实现:(使用链表实现,不使用递归) 创建结构体数据类型(记录二叉......
  • CF1039D You Are Given a Tree (树形 dp + 贪心 + 根号分治)
    CF1039DYouAreGivenaTree树形dp+贪心+根号分治题目是一个经典问题,可以用树形dp和贪心解决。设\(f_u\)表示以\(u\)节点为端点能够剩下的最长路径。考虑从叶子节点往上合并贪心,那么如果能够合并出包含\(u\)节点的大于等于\(k\)的路径,那么就合并,\(f_u=0\);否......
  • 阿里228x82y还原之递归数组解密
    声明本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!目标网站某里228分析逆向流程228递归函数str解密原理就是用数组push最后填充下,然后解密出来多了......