递归算法

算法图解——递归

大憨熊 提交于 2020-02-18 05:28:09
递归 函数自己调用自己 在用递归的同时,也可以用while循环实现 递归只是让解决方案更加清晰,并没有性能上的优势,有时候甚至循环的性能更好 “如果使用循环,程序性能可能更高;如果使用递归,程序可能更容易理解” 基线条件和递归条件 编写递归函数时,必须告诉他停止的条件 基线条件:函数不再调用自己即停止 递归条件:调用自己 def countdown ( i ) : print ( i , end = ' ' ) if i <= 1 : # 基线条件 return else : # 递归条件 countdown ( i - 1 ) countdown ( 10 ) 10 9 8 7 6 5 4 3 2 1 来源: CSDN 作者: 我是小杨我就这样 链接: https://blog.csdn.net/weixin_44478378/article/details/104361158

快速幂算法 ——递归与迭代

若如初见. 提交于 2020-02-17 23:54:27
快速幂算法讲解 递归算法: int cpow(int m,int n) { if(n==0) return 1; else if(n%2==1){ return cpow(m,n-1)*m; }else if(n%2==0) { int temp = cpow(m,n/2); return temp*temp; } } 例如:当我们已知了 2^3,那么在计算2^6不就是相当于2^3*2^3,而快速幂就是运用了这样的原理,但是,如果我们碰到的幂为奇数时怎么办?直接提出来一个幂不就好了,例如在计算2^7,将此转换成2*2^6,之后2^6继续运用上面对待偶数的办法不就好了; 总结以上啰里啰嗦的话,转换成公式就是一下: 1 )当b是奇数时,那么有 a^b = a * a^*(b-1) 2)当b是偶数时,那么有 a^b = a^(b/2) * a^(b/2) 迭代算法: int qpow(int a,int n) { int nas = 1; while(n){ if(n&1) ans *= a; a *= a; n>>=1; } return ans; } 迭代算法运用到了位运算&,将递归算法的(n%2==0)改为(n&1); 对于 a ^ b来说,若果把 b 写成2 进制,那么b 就可以写成若干二次幂之和,如13 的二进制 1101,于是3 号位 、2号位、0号位就都是1

如何k个一组反转链表

本小妞迷上赌 提交于 2020-02-17 10:58:32
之前的文章「递归反转链表的一部分」讲了如何递归地反转一部分链表,有读者就问如何迭代地反转链表,这篇文章解决的问题也需要反转链表的函数,我们不妨就用迭代方式来解决。 本文要解决「K 个一组反转链表」,不难理解: 这个问题经常在面经中看到,而且 LeetCode 上难度是 Hard,它真的有那么难吗? 对于基本数据结构的算法问题其实都不难,只要结合特点一点点拆解分析,一般都没啥难点。下面我们就来拆解一下这个问题。 一、分析问题 首先,前文 学习数据结构的框架思维 提到过,链表是一种兼具递归和迭代性质的数据结构,认真思考一下可以发现 这个问题具有递归性质 。 什么叫递归性质?直接上图理解,比如说我们对这个链表调用 reverseKGroup(head, 2) ,即以 2 个节点为一组反转链表: 如果我设法把前 2 个节点反转,那么后面的那些节点怎么处理?后面的这些节点也是一条链表,而且规模(长度)比原来这条链表小,这就叫 子问题 。 我们可以直接递归调用 reverseKGroup(cur, 2) ,因为子问题和原问题的结构完全相同,这就是所谓的递归性质。 发现了递归性质,就可以得到大致的算法流程: 1、先反转以 head 开头的 k 个元素 。 2、将第 k + 1 个元素作为 head 递归调用 reverseKGroup 函数 。 3、将上述两个过程的结果连接起来 。

动态规划和递归算法求解斐波那契数列的效率对比

五迷三道 提交于 2020-02-16 12:05:52
动态规划有效的解决了递归算法的效率低下的问题,它剔除了递归中的重叠的子问题,对每个子问题只求解一次。 斐波那契数列格式为:1、1、2、3、5、8、13、21、34、......, 递归(状态转移)函数为 f[n]=f[n-1]+f[n-2] 采用递归求解: #采用递归求解 def f_recu(n): assert isinstance(n,int),'必须输入一个整数' assert n>=1,'不能小于1' if n==1 or n==2: return 1 return f_recu(n-1) + f_recu(n-2) #测试,n=40 计算时间 %time f_recu(40) 输出: Wall time: 48.4 s 102334155 采用动态规划求解: #采用动态规划方法求解 def f_dyna(n): assert isinstance(n,int),'必须输入一个整数' assert n>=1,'不能小于1' if n == 1 or n==2: return 1 else: pre_n_2 = 1 pre_n_1 = 1 for i in range(3,n+1): target_n = pre_n_2 + pre_n_1 pre_n_1 = pre_n_2 pre_n_2 = target_n return target_n #测试,n=40 计算时间

栈与递归

谁说我不能喝 提交于 2020-02-16 00:06:38
文章目录 递归 函数调用 递归工作栈 递归算法的效率分析 递归转换为非递归 递归算法优点 递归 若在一个函数、过程或数据结构定义的内部又直接(或间接)出现定义本身的应用,则称它们是递归。 三种常使用递归的情况: 定义是递归的 例1:阶乘函数 long Fact ( long n ) { if ( n == 0 ) return 1 ; //递归终止的条件 else return n * Fact ( n - 1 ) ; //递归步骤 } 例2:Fibonacci数列 long Fib ( long n ) { if ( n == 1 || n == 2 ) return 1 ; //递归终止的条件 else return Fib ( n - 1 ) + Fib ( n - 2 ) ; //递归步骤 } 分解-求解的策略称为 分治法 采用分治法进行递归求解问题需要满足的条件: (1)能将一个问题转变成一个新问题,而新问题与原问题的解法相同或类同,不同的仅是处理的对象,并且这些处理对象更小且变化有规律 (2)可以通过上述转化而使问题简化 (3)必须有一个明确的递归出口,或称递归的边界 分治法: void p ( 参数表 ) { if ( 递归结束条件成立 ) 可直接求解; //递归终止条件 else p ( 较小的参数 ) ; //递归步骤 } 数据结构是递归的

LeetCode.509——斐波那契数

点点圈 提交于 2020-02-14 21:05:41
问题描述: 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 给定 N,计算 F(N)。 示例 : 输入:2 输出:1 解释:F(2) = F(1) + F(0) = 1 + 0 = 1. 问题分析: 由于计算任何一个第n(n >= 2)项的数都需要知道其前面两个数,即需要知道n-1和n-2是多少,然后两个相加得到结果,但是问题来了,要知道n-1,就要需要知道n-2,要知道n-2就需要知道n-3,会一直这样的循环递归下去,一直到第一个数,第二个,第三个.......再反推回来。 那就很明显了,大家第一时间想到的方法便是递归,就下来实现一下: 方法一:递归实现 public class Solution { public int fib(int n) { if(n <= 1){ return n; } return fib(n-1) + fib(n-2); } } ​ 问题分析: ​ 先看一下递归图: ​ 由于很多数的计算都要重复很多次,效率并不高,时间复杂度达到了 O(2^n),是斐波那契数计算中 时间复杂度最大,最不可取的方法。 ​ 空间复杂度:O(n),堆栈中需要的空间与 N

java例题_23 递归求年龄

时光毁灭记忆、已成空白 提交于 2020-02-14 14:40:24
1 /*23 【程序 23 求岁数】 2 题目:有 5 个人坐在一起,问第五个人多少岁,他说比第 4 个人大 2 岁。问第 4 个人岁数,他说比第 3 个 3 人大 2 岁。问第三个人,又说比第 2 人大两岁。问第 2 个人,说比第一个人大两岁。最后问第一个人,他 4 说是 10 岁。请问第五个人多大? 5 */ 6 7 /*分析 8 *除第一个人外,每个人都比前面那个人大2岁,用递归算法 9 *x2=x1+2,x3=x2+2,x4=x3+2,x5=x4+2;x1=10 10 * */ 11 12 13 package homework; 14 15 public class _23 { 16 17 public static void main(String[] args) { 18 // 第一个人10岁,共5人 19 int years=10; 20 int x=5; 21 System.out.println("第"+x+"个人的年龄为:"+NianLing(years, x)+"岁"); 22 } 23 public static int NianLing(int y,int x) { 24 if(x==1) { 25 return y; 26 } 27 else { 28 x--; 29 return NianLing(y, x)+2; 30 } 31 } 32 33 }

递归、尾递归和使用Stream延迟计算优化尾递归

ε祈祈猫儿з 提交于 2020-02-13 10:41:58
我们在学数据结构的时候必然会接触栈(Stack),而栈有一个重要的应用是在程序设计语言中实现递归。递归用途十分广泛,比如我们常见的阶乘,如下代码: 1234 public static int (int n) { if (n == 1) return 1; return n * func1(n - 1);} 就可以用递归实现,而且实现相当简洁。如果要计算n的阶乘,那么只需知道n-1的阶乘再乘以n,同理依次类推,直到当我们计算2的阶乘的时候,只需知道1的阶乘,显然这是递归终止条件,再层层向上返回,直至计算出n的阶乘即可。 从上面的分析可以看出,如果我们要进行递归求解某一问题,需要满足以下两个条件: 能将一个问题转变为另一个新问题,而新问题的解法与原问题相同或者类同,并且新问题的数据规模更小,问题简化。 使用递归的情景是当前数据规模较大,直接计算比较困难,那么可以将该问题进行分解,数据规模越来越小,计算也越来越容易,其实这是“分治法”的体现。 存在递归终止条件,或者说递归的边界。 递归的终止条件是必须的,既然当前问题可以分解,那么就必须存在一个“极限”,分解到什么程度?到哪里停止? “分治法”求解递归问题算法有一个一般形式: 1234 void p(参数列表) { if (递归终止条件成立) 直接求解; // 递归终止条件 else p(较小的参数) // 递归步骤}

1.算法设计的基本方法(二)

自古美人都是妖i 提交于 2020-02-13 02:09:06
续上一篇继续写算法设计的基本方法,递推法和递归法 3.递推法 其基本思想就是从前面的一些量推出后面的一些量,它从已知的初始条件出发,逐次推出所要求解的各中间结果和最终结果。 具体实现有两种方式: 递归的和非递归的 递归的递推求解是使用迭代法计算,自顶向下进行; 非递归的地推求解是使用迭代法计算,自底向上。 [例1-16]计算斐波那契数。斐波那契数列存在着如下递推关系: f(0)=0,f(1)=1,f(n)=f(n-1)+f(n-2),n≥2 ; 程序如下: int Fib ( int k ) { if ( k < 2 ) return k ; int f0 , f1 , i , fk ; f0 = 0 , f1 = 1 ; for ( int i = 2 ; i <= k ; i ++ ) { fk = f0 + f1 ; f0 = f1 ; f1 = fk ; } return fk ; } 4.递归法 如果一个数据对象包含它自身,则称此对象为递归的; 如果一个过程直接或间接调用它自身,则该过程是递归的。 直接调用自身称作直接递归,间接调用就称间接递归呗! 递归是构造算法的一种基本方法,它将一个复杂问题归结为若干个较为简单的问题,然后将这些较为简单问题进一步归结为更简单的问题,这个过程一直进行下去,直到归结为最简单的问题为止,这个最简单的问题即为递归终止条件,也称作 递归出口 。

从《汉诺塔》来讲递归算法

元气小坏坏 提交于 2020-02-12 23:01:35
哈喽,大家好,我是Tony: 这篇博客将以《汉诺塔》为例进行递归编程: 编程题 给定一个整数n,代表汉诺塔游戏中从小到大放置的n个圆盘,假设开始时所有的圆盘都放到左边的桌子上,想按照汉诺塔游戏规则把所有的圆盘都移到右边的柱子上。实现函数打印最优移动轨迹 举例 n=1时,打印: move from left to right n=2时,打印: move from left to mid move from left to right move from mid to right 说明 这是一个典型的汉若塔问题,汉若塔问题永远都是经典的三步走: 把n-1的盘子移动到缓冲区 把1号从起点移到终点 把缓冲区的n-1号盘子移动到终点 代码(C++): // ConsoleApplication2.cpp : 定义控制台应用程序的入口点。 //汉诺塔问题 #include "stdafx.h" #include<iostream> #include<vector> #include<string> using namespace std; void funoi2(int n, string from, string buffer, string to) { if (n==1) { cout <<"Move "<<"from "<<from<<" "<< "to "<<to<<endl; }