递归算法

递归算法的简单应用

耗尽温柔 提交于 2019-11-28 12:22:49
为了确保递归函数不会导致无限循环,它应具有以下属性: 一个简单的 基本案例(basic case) (或一些案例) —— 能够不使用递归来产生答案的终止方案。 一组规则,也称作 递推关系(recurrence relation) ,可将所有其他情况拆分到基本案例。 1、以相反的顺序打印字符串 /** 输入:["h","e","l","l","o"] 输出:["o","l","l","e","h"] */ public class PrintReverseDemo { public static void main(String[] args) { printReverse("apple".toCharArray()); } private static void printReverse(char[] str) { helper(0, str); } private static void helper(int index, char[] str) { if (null == str || index >= str.length) { return; } helper(index + 1, str); System.out.print(str[index]); } } 2、两两交换链表中的节点 /** * 给定 1->2->3->4, 你应该返回 2->1->4->3. */

五大常用算法之二——动态规划

99封情书 提交于 2019-11-28 08:18:10
文章目录 1.动态规划算法简介 1.1 基本定义 1.2 问题的特征 1.3 求解步骤 2.动态规划的经典问题 2.1 0-1背包问题 2.1.1 问题描述 2.1.2 问题状态的描述 2.1.3 动态规划递归方程 2.2 最短路径问题 2.2.1 所有顶点对之间的最短路径问题 2.2.2 带负值的单源最短路径问题 参考资料 1.动态规划算法简介 动态规划(Dynamic Programming) ,将原问题分解为相对简单的子问题来求解,常使用于有 覆盖子问题 和 最优子结构 性质的问题。 1.1 基本定义 在动态规划中,我们要考察一系列的抉择来确定 最优抉择 是否包含最优抉择子序列。即要解决一个给定问题,我们需要将其分解成 子问题 ,然后通过对子问题的求解来逐步构造全局的解。 注意!!! 这里的子问题和 分治算法 中的子问题是不一样的: 分治算法中分解的子问题看成是 独立的 ,通常通过递归来做,例如归并排序; 动态规划分解后的子问题相互间有一定的联系,还有可能有重叠的部分,可迭代、可递归求解。 1.2 问题的特征 通常能通过动态规划求解的问题,有两个明显的特征: 最优子结构 :原问题的最优解包含其子问题的最优解;全局的最优解可通过子问题的最优解构造,是能用 动态规划求解问题的必要条件。(例如最短路径问题) 重叠子问题 :一个问题被分解成多个子问题,其中有些子问题被重复计算多次

python中对递归函数的认识

我们两清 提交于 2019-11-28 03:37:54
1 ,递归的定义 递归(Recursion Algorithm,递归算法) 是指通过 重复将问题分解为同类的子问题 而解决问题的办法。计算理论证明递归的作用可以完全取代循环。 重复 :凡是通过循环语句可实现的,都可以通过递归来实现。 将问题分解为同类的子问题: 如持续循环的运算操作、持续循环的判断操作,它们的每次循环都是同样的一个“动作”,这个“动作”就是一个子问题的。 利用函数实现递归算法的过程就是递归函数。是通过自己调用自己来实现递归算法。 2,递归函数在内存中的运行原理 递归一次,就在内存中开辟一个新的地址空间,记录递归过程状态,一直递归分解到最小范围,最后得出要么找到对应的值,要么返回找不到的结果。 通俗的讲,其实是在调用栈的进栈、出栈操作过程。每递归调用自己一次,就进栈一次,并在栈列表里记录调用的内容;每返回一次,就是出栈弹出值的过程,并把值返回到上一个栈列表里,最后返回所求最终答案。 3,举例 1 #定义函数 2 def recursion_sum(num): 3 if num==1: 4 return num 5 tt=recursion_sum(num-1)+num 6 print('第%d次递归'%(num)) 7 print('返回值%d在内存中的地址:%d'%(tt,id(tt))) 8 return num 9 #调用函数 10 print

C_函数_递归

我们两清 提交于 2019-11-28 03:13:56
1.定义 一个函数直接或间接地调用自己 2.不同函数间的相互调用 ​ 1 #include<stdio.h> 2 3 void a(void); //函数声明 4 void b(void); 5 void c(void); 6 7 void a(void) 8 { 9 printf("aaaa\n"); //②执行完这一步,然后跳转到b()函数 10 b(); 11 printf("1111\n"); //⑥执行完a()剩下语句后回到main函数 12 } 13 14 void b(void) 15 { 16 printf("bbbb\n"); //③执行完这一步跳转到c()函数 17 c(); 18 printf("2222\n"); //⑤执行完b()剩下的语句后回到a() 19 } 20 21 void c(void) 22 { 23 printf("cccc\n"); 24 printf("3333\n"); //④执行完c()后回到b()函数执行剩下语句 25 } 26 27 int main(void) //①程序从main函数开始 28 { 29 a(); 30 31 return 0; 32 } 输出:​ ​aaaa bbbb cccc 3333 2222 1111 3.递归举例 1 #include<stdio.h> 2 3 void f(int n) 4 { 5

Python学习日记(十三) 递归函数和二分查找算法

限于喜欢 提交于 2019-11-28 03:11:51
什么是递归函数? 简单来说就是在一个函数中重复的调用自己本身的函数 递归函数在调用的时候会不断的开内存的空间直到程序结束或递归到一个次数时会报错 计算可递归次数: i = 0 def func(): global i print('i = {}'.format(i)) i += 1 return func() func()            #.....i = 994 i = 995 RecursionError: maximum recursion depth exceeded while calling a Python object 在这里我们修改我们可递归的次数: import sys sys.setrecursionlimit(1000000) i = 0 def func(): global i print('i = {}'.format(i)) i += 1 return func() func() #...i = 3924 i = 3925 如果还想递归更多的次数,就必须要提升计算机的性能了 递归函数的 优点 就是能让一个问题变得简单,但 缺点 就是太占用内存,因此递归函数不适合解决需要大规模递归运算的问题 二分查找算法: 这个被查询的列表必须是一个 有序 的列表 def find(l,aim,start = 0,end = None): end = len(l

剑指offer-树相关

孤人 提交于 2019-11-28 03:02:05
树相关 1.重建二叉树 1 class Solution { 2 public: 3 TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { 4 if(pre.size() == 0 || vin.size() == 0) 5 return nullptr; 6 return constructCore(pre, vin, 0, pre.size()-1, 0, vin.size()-1); 7 } 8 9 TreeNode* constructCore(vector<int> pre,vector<int> vin, int sp, int ep, int si, int ei) 10 { 11 //sp, ep 确定先序中树的范围,si,ei确定中序的子树范围 12 //先序头就是根 13 int rootValue = pre[sp]; 14 TreeNode* root = new TreeNode(rootValue); 15 if(sp == ep) 16 { 17 if(si == ei && pre[sp] == vin[si]) 18 return root; 19 } 20 //中序找到根,分为左右子树 21 int index = si; 22 while(index <= ei &

JavaScript函数尾调用与尾递归

安稳与你 提交于 2019-11-28 01:56:33
什么是函数尾调用和尾递归 函数尾调用与尾递归的应用 一、什么是函数的尾调用和尾递归 函数尾调用就是指函数的最后一步是调用另一个函数。 1 //函数尾调用示例一 2 function foo(x){ 3 return g(x); 4 } 5 //函数尾调用示例二 6 function fun(x){ 7 if(x > 0){ 8 return g(x); 9 } 10 return y(x); 11 } 调用最后一步和最后一行代码的区别,最后一步的代码并不一定会在最后一行,比如示例二。还有下面这一种不能叫做函数尾调用: 1 // 下面这种情况不叫做函数尾调用 2 function fu(x){ 3 var y = 10 * x; 4 g(y); 5 } 为什么这种情况不叫作函数的尾调用呢?原因很简单,因为函数执行的最后一步是return指令,这个指令有两个功能,第一个功能是结束当前函数执行,第二个功能是将指令后面的数据传递出去(函数返回值)。而这个return指令不管有没有声明都会执行,没有声明的情况下返回的数据是undefined,所以上面的代码实际上是以下结构: 1 function fu(x){ 2 var y = 10 * x; 3 g(y); 4 return undefined; 5 } return指令是先关闭函数,然后再返回数据。说到这里,就会引发一个问题出来

类型和程序设计语言

我的梦境 提交于 2019-11-27 19:10:20
编程语言的类型系统为何如此重要? - 知乎 https://www.zhihu.com/question/23434097/answer/43057230 《类型和程序设计语言》.pdf - 免费高速下载 - 皮皮盘-收入最高的网盘 当前标签:简单易懂的程序语言入门小册子 当前标签:简单易懂的程序语言入门小册子 简单易懂的程序语言入门小册子(9):环境,引入环境 古霜卡比 2014-05-16 05:46 阅读:793 评论:2 简单易懂的程序语言入门小册子(8):基于文本替换的解释器,小结 古霜卡比 2014-05-08 08:55 阅读:883 评论:5 简单易懂的程序语言入门小册子(7):基于文本替换的解释器,加入continuation,重构解释器 古霜卡比 2014-05-03 10:27 阅读:643 评论:0 简单易懂的程序语言入门小册子(1.5):基于文本替换的解释器,递归定义与lambda演算的一些额外说明 古霜卡比 2014-05-02 11:41 阅读:753 评论:0 简单易懂的程序语言入门小册子(6):基于文本替换的解释器,引入continuation 古霜卡比 2014-04-28 11:18 阅读:926 评论:2 简单易懂的程序语言入门小册子(5):基于文本替换的解释器,递归,不动点,fix表达式,letrec表达式 古霜卡比 2014-04-23

C语言程序设计(七)

我们两清 提交于 2019-11-27 18:36:28
第七章 函数 分而治之: 把较大的任务分解成若干较小、较简单的任务,并提炼出公用任务的方法 函数是C语言中模块化程序设计的最小单位,既可以把每个函数都看作一个模块,也可以将若干相关的函数合并成一个模块 信息隐藏: 把函数内部的信息对不需要这些信息的其他模块隐藏起来,让使用者不必关注函数内部是如何做的 只知道它能做什么以及如何使用它即可,从而使得整个程序的结构更加紧凑,逻辑也更清晰 标准库函数:使用ANSIC的库函数,必须在程序的开头将该函数所在的头文件包含进来 自定义函数 函数在使用之前必须定义 函数名是函数的唯一标识,用于说明函数的功能 为了便于区分,通常变量名用小写字母开头的单词组合而成,函数名则用大写字母开头的单词组合而成 Windows风格: 函数名使用“动词”或者“动词+名词”的形式 变量名使用“名词”或者“形容词+名词”的形式 函数体必须用一对花括号{}包围,这里的花括号是函数体的界定符 在函数内部定义的变量只能在函数体内访问,称为 内部变量 函数头部参数表里的变量,称为形式参数,也是内部变量 形参表是函数的入口 函数名相当于运算的规则,形参表里的形参相当于运算的操作数,函数的返回值就是运算的结果 若函数没有返回值,则需用void定义返回值的类型 若函数不需要入口参数,则用void代替函数头文件形参表中的内容 在函数定义的前面写上一段注释来描述函数的功能及其形参

左神算法第八节课:介绍递归和动态规划(汉诺塔问题;打印字符串的全部子序列含空;打印字符串的全排列,无重复排列;母牛数量;递归栈;数组的最小路径和;数组累加和问题,一定条件下最大值问题(01背包))

余生颓废 提交于 2019-11-27 16:55:36
暴力递归: 1,把问题转化为规模缩小了的同类问题的子问题 2,有明确的不需要继续进行递归的条件(base case) 3,有当得到了子问题的结果之后的决策过程 4,不记录每一个子问题的解 动态规划 1,从暴力递归中来 2,将每一个子问题的解记录下来,避免重复计算 3,把暴力递归的过程,抽象成了状态表达 4,并且存在化简状态表达,使其更加简洁的可能 一:递归 1. 汉诺塔问题 汉诺塔问题(不能大压小,只能小压大),打印n层汉诺塔从最左边移动到最右边的全部过程。 左中右另称为 from、to、help。 划分子问题: 1、先把1~n-1从from移动到help; 2、把单独的n移动到to; 3、1~n-1从help移动到to; 时间复杂度就是:T(n) = T(n-1) + 1 + T(n-1) = 2T(n-1)+1(一个等比公式)。T(n-1)是移动到help;1是从from直接移动到to;T(n-1)是把全部n-1挪回去。总的步数是2的N次方减一。 2. 打印一个字符串的全部子序列,包括空字符串 例如:一个字符串awbcdewgh 他的子串:awbc,awbcd,wbcde...很多个子串,但是都是连续在一起 他的子序列:abc,abcd,abcde...很多个子序列,但是子序列中的字符在字符串中不一定是连在一起的 所以 子串!=子序列 思路:穷举,例如“abc”