递归算法

分治法的基本思想

拟墨画扇 提交于 2019-11-26 12:09:18
分治法得基本思想是将一个规模为n的问题分解为k个规模为m的相互独立且与原问题解法相同的子问题,然后将子问题的解合并得到原问题的解。 由此可见,分治法设计出的程序一般是递归算法,设解决一个规模为1的问题需要1个单位时间,再设将k个子问题的解合并为原问题的解所需时间为f(n),则递归算法的时间复杂度为: 解递归方程: , 主定理: 当 时,T(n)=O( ); 当 时,T(n)=O ; (此处logn底数为2) 当 时,T(n)=O(f(n)); 来源: CSDN 作者: FRANKENSTEIN0 链接: https://blog.csdn.net/qq_41678225/article/details/100707762

分治法的概念以及应用

99封情书 提交于 2019-11-26 12:08:12
分治法:“分久必合,合久必分” 哈哈,其实分治法应该理解为分而治之的方法,它的基本思想是把一个大的问题比较复杂的问题,拆分成多个规模较小的子问题,然后解决这些子问题的难度就比原来大的问题简单的多。但是这个拆分是要注意如何去拆分按什么思路去拆分因为拆分出来的这种子问题要求和原来的问题是同样的结构的问题(也可以说是相同的问题),只是复杂度小一些规模小一些,拆分出来的子问题又可以用同样的方式进一步的拆分。那么既然如此我们解决这个问题时候所采用的函数是不是能够用同样的函数去解决问题呢?答案是肯定的。所以再分治法中往往要用到递归的技术来解决问题。递归技术在下文单独篇。以上就是我对分治法基本思想的理解。 所以分治法它会先做分解,分解之后它会把一系列小的问题给它解决掉,然后再把小的问题进行相应的汇合,一步一步整合合并,合并之后得到最终的原来的初始问题的解决方案。就是按这种思路来解决问题,要利用到分治法来解决问题往往要对这个问题本身有一定的要求,首先这个问题它的规模缩小到一定的程度要能够容易的解决,否则就失去了拆分它的意义。其次这个问题必须要能够分解成若干个规模较小的相同问题,如果分出来的是不同问题那也不行。最后要能够利用到这个问题,分解出来的子问题的解能够合并为原来问题的解。同时各个子问题要求是相互独立的,不相互独立也不行。这就是分治法的基本思想以及对分治法应用的基本要求。 递归技术

线段树

北城余情 提交于 2019-11-26 11:09:45
区间线段树: const int MAXM=100000; int a[MAXM+5]; ll st[(MAXM<<2)+5],lazy[(MAXM<<2)+5]; inline void push_up(int o) { st[o]=st[o<<1]+st[o<<1|1]; } inline void push_down(int o,int l,int r) { if(lazy[o]) { lazy[o<<1]+=lazy[o]; lazy[o<<1|1]+=lazy[o]; int m=(l+r)>>1; st[o<<1]+=lazy[o]*(m-l+1); st[o<<1|1]+=lazy[o]*(r-m); lazy[o]=0; } } void build(int o,int l,int r) { if(l==r) st[o]=a[l]; else { int m=(l+r)>>1; build(o<<1,l,m); build(o<<1|1,m+1,r); push_up(o); } lazy[o]=0; } void update(int o,int l,int r,int a,int b,ll v) { if(a<=l&&r<=b) { lazy[o]+=v; st[o]+=v*(r-l+1); return; } else { push_down(o,l,r);

递归函数

怎甘沉沦 提交于 2019-11-26 11:02:46
我们在前面的章节中,很多次的看到了在函数中调用别的函数的情况。如果一个函数在内部调用了自身,这个函数就被称为递归函数。 What?函数可以自己调用自己?那不是成为了“衔尾蛇”?会不会进入死循环,永远退出不了?我们先看一个例子,典型的高斯求和问题,1+2+3+4+…+99+100,不使用递归的话,我们可以用循环,这么做: def sum_number(n): """ 1-100相加 :param n: :return: """ total = 0 for i in range(1, n + 1): total += i return total print(sum_number(100)) 但如果使用递归函数来写,是这样的: def sum_number(n): """ 递归函数1——100 :param n: :return: """ if n <= 0: return 0 return n + sum_number(n - 1) print(sum_number(100)) 分析一下代码,当n小于等于0的时候,直接给出和值为0,这句不能省。当n大于0时,结果是n加上 sum_number(n-1) 。这里的 sum_number(n-1) 又是一次 sum_number 函数的调用,不过参数的值变成了n-1,要得 sum_number(n) 到的值就必须等待 sum_number

C#递归算法来计算阶乘的方法

南楼画角 提交于 2019-11-26 09:59:20
通过一个简单实例来说明使用C#递归算法来计算阶乘的方法。一般来说,想要实现一个阶乘,比如6 5 4 3 2*1这个简单阶乘,一般会首先想到使用循环遍历,如下面代码所示: class Program { static void Main ( string [ ] args ) { Console . WriteLine ( "请输入一个数" ) ; int number = Convert . ToInt32 ( Console . ReadLine ( ) ) ; double result = JieCheng ( number ) ; Console . WriteLine ( number . ToString ( ) + "的阶乘结果是:" + result . ToString ( ) ) ; Console . ReadKey ( ) ; } public static double JieCheng ( int number ) { if ( number == 0 ) { return 0 ; } //初始值必须设置为1 double result = 1 ; for ( int i = number ; i >= 1 ; i -- ) { result = result * i ; } return result ; } } 但是这种阶乘其实还有另一种实现方式:6

算法笔记——递归练习

你离开我真会死。 提交于 2019-11-26 05:58:42
1、分治思想与递归手段 首先,分治的英文是divide and conquer, 也就是分而治之的意思,基本策略是将原问题划分为若干个规模较小而结构与原问题相同或相似的子问题,然后分别解决这些子问题,最后合并子问题的解就能得到原问题的解。 一般我们都是使用递归的手段去实现分治思想 2、递归 概念:通过反复调用自身函数, 但是每次都把问题范围缩小,直到范围缩小到可以直接得到边界数据的结果,然后再在返回的路上求出结果。正是因为递归与分治的思想非常接近,所以我们会递归来解决分治问题。 递归的两个重要概念:递归边界与递归式。递归式是将原问题分解为若干个子问题的手段,递归边界则是分解的尽头 3、递归的具体例子练习 阶乘: n!= n * n-1 * n-1 * ... * 1, 写成递归式就是 n! = ( n-1 ) ! * n, 可以看出跳出递归的边界就是n为1或0的情况(因为1!=0!=0 ,所以都可以作为递归边界) #include<stdio.h> #include<iostream> using namespace std; int f(int n) { if(n == 0) return 1; //这个判定就是递归边界 else return f(n-1) * n; //f(n) = f(n-1) * n就是递归式 } int main() { int n; cin>>n;

静态,非静态,递归

≯℡__Kan透↙ 提交于 2019-11-26 00:32:15
#静态与非静态 static表示静态的。 他需要常驻内存,一直占用内存,无法进行垃圾回收,需慎用,他在那种情况适用呢? 不管哪个对象调用,结果都是一样的(这个结果的一致指的是你输出的数据图案的一致性等等),调用可直接用类名字调用,不许要变量名了。和对象就没有关系了。 之前所说的对象是是Java中所面对的东西,也就是你要用程序解决问题的哪一个,Java是面对对象的语言, 建立方法最好是单独定义一个类,类里面存在共同的特征。就相当于一个模板 当你建立方法的时候你最好单独把方法集中放在一个类中,,这样不同的对象皆可应用这个类,用 “ ,“表示所属关系 静态方法和非静态方法的调用内存方式是不一样的,静态得是占了一个存储空间,他就不变了,而非静态是随你调用方法(通过new调用构造方法)时开始开辟内存,一个变量对应一个指定的内存,当你调用完以后,你开辟的内存随之消失, ##静态方法(static method) 与静态成员变量一样,属于类本身,在类装载的时候被装载到内存中,不自动进行销毁,会一直存在内存中,直到JVM关闭; ##非静态方法(non-static method) 又称实例化方法,属于实例对象,实例化之后才会分配内存,必须通过类的实例来引用,当实例对象被JVM回收之后,也跟着消失 ##静态方法和实例方法的区别 1.生命周期 静态方法的生命周期从进程创建时就开始,一直到进程结束

为什么你学不会递归?告别递归,谈谈我的经验

吃可爱长大的小学妹 提交于 2019-11-25 19:52:38
可能很多人在大一的时候,就已经接触了递归了,不过,我敢保证很多人初学者刚开始接触递归的时候,是一脸懵逼的,我当初也是,给我的感觉就是,递归太神奇了! 可能也有一大部分人知道递归,也能看的懂递归,但在实际做题过程中,却不知道怎么使用,有时候还容易被递归给搞晕。也有好几个人来问我有没有快速掌握递归的捷径啊。说实话,哪来那么多捷径啊,不过,我还是想写一篇文章,谈谈我的一些经验,或许,能够给你带来一些帮助。 为了兼顾初学者,我会从最简单的题讲起! 递归的三大要素 第一要素:明确你这个函数想要干什么 对于递归,我觉得很重要的一个事就是, 这个函数的功能是什么 ,他要完成什么样的一件事,而这个,是完全由你自己来定义的。也就是说,我们先不管函数里面的代码什么,而是要先明白,你这个函数是要用来干什么。 例如,我定义了一个函数 // 算 n 的阶乘(假设n不为0) int f(int n){ } 这个函数的功能是算 n 的阶乘。好了,我们已经定义了一个函数,并且定义了它的功能是什么,接下来我们看第二要素。 第二要素:寻找递归结束条件 所谓递归,就是会在函数内部代码中,调用这个函数本身,所以,我们必须要找出 递归的结束条件 ,不然的话,会一直调用自己,进入无底洞。也就是说,我们需要找出 当参数为啥时,递归结束,之后直接把结果返回 ,请注意,这个时候我们必须能根据这个参数的值,能够 直接