递归算法

重读算法导论之算法基础

本小妞迷上赌 提交于 2019-12-27 14:51:32
重读算法导论之算法基础 插入排序 ​ 对于少量数据的一种有效算法。原理: 整个过程中将数组中的元素分为两部分,已排序部分A和未排序部分B 插入过程中,从未排序部分B取一个值插入已排序的部分A 插入的过程采用的方式为: 依次从A中下标最大的元素开始和B中取出的元素进行对比,如果此时该元素与B中取出来的元素大小关系与期望不符,则将A中元素依次向右移动 ​ 具体代码如下: public static void insertionSort(int[] arr) { // 数组为空或者只有一个元素的时候不需要排序 if (arr == null || arr.length <= 1) { return; } // 开始插入排序,先假设元素组第一个元素属于已经排好序的A部分,依次从B部分取出元素,进行比较插入 for (int j = 1; j < arr.length; j++) { int key = arr[j]; int i = j - 1; for (; i >= 0; i--) { if (arr[i] > key) { arr[i + 1] = arr[i]; } else { break; } } arr[i+1] = key; } } ​ 易错点为,最后应该是设置arr[i + 1] = key。 可以设想假设A中所有元素都比B中选出来的数小的时候

点分治

荒凉一梦 提交于 2019-12-27 07:28:06
点分治 蒟蒻迟迟没法开点分治的坑,主要是因为最近找了几道点分治题,全都可以用 长链剖分 写,由于博主又懒又菜,所以点分治没有得到练习的机会。终于,最近安排了专题分享,最菜的chd捡了一个分治专题,不得不学学这些东西了。 举个简单的例子,我们对树上的路径有一些询问。我们考虑对于树上的任意一个点,它的子树中的路径可以分为两类:一种是 经过根节点的路径 ,一种是 不经过根节点的路径 。由于不经过根节点的路径可以递归处理,这样分治的思路就很明显了。对于每一个点的子树,可以选取一个点作为根节点,递归到当前层时,只处理过根节点的路径,然后递归处理我们选定的根节点的儿子,就可以考虑到所有路径。 但是需要考虑一种极端情况:假如题目给出了一条长度为 \(n\) 的链,而我们第 \(i\) 层递归选定第 \(i\) 个点作为根节点往下递归,那就要递归 \(n\) 层,总的复杂度无法保证。这时我们就要考虑选取根节点的技巧了,每次递归选取 树的重心 为根节点,由于重心有一个性质:删除重心后得到的森林中的每一棵树的大小都不超过原树的一半,这样就能保证递归层数是 \(logn\) 层。 那么怎样求重心呢?考虑树的重心定义为一棵树中删除它后能使得到的森林中最大的树最小的点。一遍dfs就能求出,具体的实现下面会有。 接下来看题吧。 P4178 Tree 做这道题之前可以先看看它的弱化版 CF161D

递归和递推 && 动态规划算法

风流意气都作罢 提交于 2019-12-27 02:18:56
借鉴:http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741374.html 动态规划算法: 一、算法思想: 将待求解的问题分解成若干个子问题,并存储子问题的解而避免计算重复的子问题,并由子问题的解得到原问题的解。 l动态规划算法通常用于求解具有某种最优性质的问题。 l动态规划算法的基本要素:最优子结构性质和重叠子问题。 1、l最优子结构性质: 问题的最优解包含着它的子问题的最优解 。即不管前面的策略如何,此后的决策 必须是基于当前状态 (由上一次决策产生)的最优决策。 2、重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些问题被反复计算多次。对每个子问题只解一次,然后将其解保存起来,以后再遇到同样的问题时就可以直接引用,不必重新求解 二、特征: 1. 动态规划一般解决最值(最优,最大,最小,最长……)问题; 2. 动态规划解决的问题一般是离散的,可以分解(划分阶段)的; 3. 动态规划解决的问题必须包含最优子结构,即可以由(n-1)的最优推导出n的最优。 三、动态规划算法的4个步骤: 1. 刻画最优解的结构特性. (一维,二维,三维数组) 将(1,2,3,4,5.....i-1,i)状态的值存到数组中 2. 递归的定义最优解. (状态转移方程) 3. 以自底向上的方法来计算最优解. 4.

Contest100000586 - 《算法笔记》4.6小节——算法初步->two pointers

大憨熊 提交于 2019-12-27 00:43:45
常用模板 two pointers:利用问题本身与序列的特性,使用两个下标 i,j 对序列进行扫描(可以同向扫描,也可以反向扫描),以较低的复杂度(一般是 O ( n ) O(n) O ( n ) )解决问题。 定和问题 给定一个 递增 的 正整数序列 和一个正整数M,求序列中的两个 不同位置 的数a和b,使得它们的和恰好为M,输出 所有 满足条件的方案。 模板如下: while ( i < j ) { if ( a [ i ] + a [ j ] == m ) { cout << i << ' ' << j ; ++ i ; -- j ; } else if ( a [ i ] + a [ j ] < m ) ++ i ; else -- j ; } 由于 i 的初值为0,j 的初值为n - 1(i,j 分别指向序列的第一个和最后一个元素),而 i 只递增,j 只递减,循环当 i >= j 时停止,因此 i 和 j 的操作最多为n次。即时间复杂度为 O ( n ) O(n) O ( n ) 。 序列合并问题 假设有两个递增序列A与B,要求将它们合并为一个递增序列C。设置两个下标 i 和 j,初值均为0,分别指向序列A和序列B的第一个元素。 int Merge ( int A [ ] , int B [ ] , int C [ ] , int n , int m ) { int i

python之函数

谁说我不能喝 提交于 2019-12-26 21:38:09
Python之函数 标签(空格分隔): 函数 现在老板要求你写一个监控程序,24小时全年无休的监控你们公司的网站服务器的系统的状况,当CPU、memory、disk等指标的使用量超过阀值时即发邮件警报 你会采取如下的方法: 2.上述代码是实现了功能但是重复代码太多了:不易维护,如果日后需要修改发邮件的代码,就会很麻烦,每个地方都要遍历一遍; 3.因此只需要把重复的代码提取出来,放在一个公共的地方,起一个名字,以后谁想用这段代码,就通过这个名字调用就行了,如下: 例如:如下的一个简单的函数: def syhi():#the name of def print("hello world") syhi()# 调用函数 备注:函数名是指向内存这段代码的地址,只有加上括号是执行内存里面的具体的内容; 另一种内容是带参数的函数:例如当你想用同一个函数,但是有些地方又是不一样的,这时候怎么办呢,就使用参数; a=7 b=5 c=a**b print(c) #另一种是函数的形式: def calc(x,y) res=x**y return res # return the result c =calc(a,b) print(c) 放了参数的函数在调用的时候一定要传参数,不然会报错的; 函数的特性:减少重复代码,使程序变的可扩展,使程序变得易于维护; 函数的默认参数 1.形参:

尾递归是个什么鬼

自古美人都是妖i 提交于 2019-12-26 08:49:21
“普通程序员使用迭代,天才程序员使用递归” 大家都说递归好用,却也都在抱怨递归过程占用内存的弊病。   以上是博主学习编程以来一直困惑的问题,能不能使用外部给的一个储存空间,使用一种近似for循环的机制解决递归爆栈,但是总有一些细节感觉不妥。这过程中内存问过一些比我牛的大佬,仍没能得以解决,知道在《图解算法》中看到“尾递归”这三个字。。。 聊聊尾递归,说尾递归,首先要说说尾调用和递归这两个小概念:   “尾调用”是指一个函数里的最后一个动作是一个函数调用的情形:即这个调用的返回值直接被当前函数返回的情形。这种情形下该调用位置为尾位置。(维基百科这样解释)   “递归”就是程序不断的调用自己本身,递归函数调用顺序:         a.调用开始前,调用方(或函数本身)会往栈上压相关的数据,参数,返回地址,局部变量等         b.执行函数         c.清理栈上相关的数据,返回   “尾递归”:顾名思义,就是兼顾“尾调用”和“递归”两者优点的一种不同的“递归”。这一种依赖于编译器的帮助实现的递归方式,并不是每一种语言都可以实现。       C语言可以实现,python就不能实现这种很奇妙的递归方式。 尾递归了解了,防止递归爆栈的方式也知道了,但是python中的递归内存问题还是本人的困惑,希望有一天,能和龟叔级别的人物聊聊类似的问题的解决方案。 努力更新中。。。

转(Java中的递归思想)

纵饮孤独 提交于 2019-12-25 22:38:35
解释:程序调用自身的 编程 技巧叫做递归。 程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。 递归的三个条件: 边界条件 递归前进段 递归返回段 当边界条件不满足时,递归前进;当边界条件满足时,递归返回。 下面通过两个示例程序来说明: 使用 Java 代码求5的阶乘。(5的阶乘=5*4*3*2*1) [java] package org.wxp.recursion; /** * 计算5的阶乘(result = 5*4*3*2*1) * @author Champion.Wong * * */ public class Test01 { public static void main(String[] args) { System.out.println(f(5)); } public static int f(int n) { if (1 == n) return 1; else return n*(n-1); } } 此题中,按照递归的三个条件来分析: (1

c# 菜单无限极分类-利用递归

寵の児 提交于 2019-12-25 18:51:55
表结构: 前台代码: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="RightDGExercise.WebForm1" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:TreeView ID="TreeView1" runat="server"> </asp:TreeView> </div> </form> </body> </html> 后台代码: public partial class WebForm1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (

【多项式】FFT

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-25 03:55:13
【多项式】FFT Preface 本文对所有 \(\LaTeX\) 编译后生成的文本共有大约 \(7000\) 字,其中前半部分为前置知识部分,介绍了多项式的有关概念、运算法则以及复数的概念、运算法则以及单位根有关内容,并证明了蝴蝶操作所用到的有关复数的两个重要引理公式。如果你对上述内容已经有了解,可以跳过 Pre-knowledge 部分。 Pre-knowledge 部分大约有 \(2000\) 字。 由于内容比较长,本文还没有经审阅人完全审阅完成,如果您发现了文本中的错误,请私信或评论我指出。 Pre-knowledge 多项式 Definition 称一个关于 \(x\) 的式子 \[f(x) = \sum_{i = 0}^{n} a_i \times x^i\] 为一个 \(n\) 次多项式,其中 \(a_i\) 为常数。称 \(n\) 为 \(f(x)\) 的次数。显然, \(f(x)\) 可以看做一个关于 \(x\) 的 \(n\) 次函数 \(y = f(x)\) 。 回忆初中解析几何最后一个大题的第一问,正常情况下都是给定三个点的坐标,求一个关于 \(x\) 的二次曲线解析式方程。而类似的如果求一条直线的解析式,则需要给出两个点的坐标。 类似的,对于如果想要确定一个 \(n\) 次函数的解析式,则需要 \(n + 1\) 个点的坐标。这是因为一个 \(n\)

递归解决汉诺塔问题

醉酒当歌 提交于 2019-12-25 02:13:29
题目来自百度百科: 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。 大梵天 创造世界的时候做了三根 金刚石 柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。 c语言实现(假设最开始放64片黄金圆盘的柱子为A, 要移动到C柱子上,借助的介质为B柱子): 1 #include <stdio.h> 2 /* 3 * 伪算法(要移动盘子的柱子为A,借助的介质柱子为B,移动到目的柱子为C. 4 * 如果盘子数为1,则直接将盘子从A柱子移到C柱子。 5 * 否则: 6 * step1:将A柱子上的N-1个盘子借助于C柱子移动到B柱子上。 7 * step2:将A柱子上的第N个盘子直接移动到C柱子上。 8 * step3:将B柱子上的N-1个盘子借助A柱子移动到C柱子上。 9 */ 10 11 void hanoi( int n, char A, char B, char C) { 12 if ( 1 == n) { 13 printf( " 将编号为%d的盘子从%c柱子直接移动到%c柱子\n " , n, A, C); 14 } else { 15 hanoi(n - 1 , A, C, B); 16 printf( " 将编号为