pascal中级教程第二章递归与递推

合集下载

算法总结之递推与递归

算法总结之递推与递归

算法总结之递推与递归递推算法递归算法⼤致包括两⽅⾯的内容:1)递归起点; 2)递归关系递推起点递归起点⼀般由题⽬或者实际情况确定,不由递归关系推出。

如果⽆法确定递归起点,那么递归算法就⽆法实现。

可见,递归起点是递归算法中的重要⼀笔。

递推关系递归关系是递归算法的核⼼。

常见的递归关系有以下⼏项:1)⼀阶递推;2)多阶递推;3)间接递推;4)逆向递推;5)多维递推。

下⾯通过栗⼦来详细介绍⼀下上述类别的递推关系。

1. ⼀阶递推在计算f(i)时,只⽤到前⾯项中的⼀项,如等差数列。

公差为3的等差数列,其递推关系为:f(i)=f(i-1)+3eg. 平⾯上10条直线最多能把平⾯分成⼏部分?分析:以直线数⽬为递推变量,假定i条直线把平⾯最多分成f(i)部分,则f(i-1)表⽰i-1条直线把平⾯分成的最多部分。

在i-1条直线的平⾯上增加直线i,易得i与平⾯上已经存在了的i-1条直线最多各有⼀个交点,即直线i最多被分成i段,⽽这i段将会依次将平⾯⼀分为⼆,即直线i将最多使平⾯多增加i部分。

所以,递推关系可表⽰为:f(i)=f(i-1)+i易得当0条直线时,平⾯为1部分。

所以f(0)=1为递推起点。

上述分析可⽤下⾯代码表⽰(c++):#define MAX 100int f[MAX] //存放f(i)int lines(int n){//输⼊n为直线数⽬//输出最多部分数int i;f(0)=1;for(i=1;i<=n;i++){f[i]=f[i-1]+3;}return f[i];}2. 多阶递推在计算f(i)时,要⽤到前⾯计算过的多项,如Fibonacci数列。

eg.求Fibonacci的第10项。

分析:总所周知,Fibonacci数列中的第n项等于第n-1项加上n-2项。

所以递推关系为f(i)=f(i-1)+f(i-2);且f[0]=f[1]=1。

C++代码如下:#define MAX 100int f[MAX];int fib(int n){//输⼊n为项数//输出第n个fib数int i;f[0]=0;f[1]=1;for(i=2;i<=n;i++){f[i]=f[i-1]+f[i-2];}return f[n]}3. 间接递推在计算f[i]时需要中间量,⽽计算中间量要⽤到之前计算过的项。

递归递推

递归递推

第二章递规与递推2.1 遍历问题源程序名travel.???(pas, c, cpp)可执行文件名travel.exe输入文件名travel.in输出文件名travel.out【问题描述】我们都很熟悉二叉树的前序、中序、后序遍历,在数据结构中常提出这样的问题:已知一棵二叉树的前序和中序遍历,求它的后序遍历,相应的,已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。

然而给定一棵二叉树的前序和后序遍历,你却不能确定其中序遍历序列,考虑如下图中的几棵二叉树:a a a a/ / \ \b b b b/ \ / \c c c c所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同。

【输入】输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。

【输出】输出可能的中序遍历序列的总数,结果不超过长整型数。

【样例】trave1.in trave1.outabc 1bca【算法分析】在肯定有解的情况下,上述算法最终可以递归调用到0、1个结点,如果有多组解,那么调用到两个结点时,如先序为ab、后序为ba,此时有可能有如下两种结构:a a/ \b b这两种结构的中序遍历结果分别为:ba、ab,有两种。

根据分步相乘的原理,对比两个字符串,每出现一次如上的情况,可能有的结构数目(结构不同,中序遍历结果也不同,因此可能有的二叉树结构的数目就是可能有的中序遍历结果数目)就乘以2一次,最终得到总的数目。

这也可以理解为一种递推的方法。

从这里可以看到,在肯定有解的情况下,给定先序遍历的结果和后序遍历的结果,可能有2n种可能的结构,也就是中序遍历可能得到2n种不同的结果,其中n>=0。

那么这里的n最大可能是多少呢?可以证明n的最大值为字符串的长度加1整除2。

【参考程序】program fgdjfk;var i,j,m,sum:longint;s1,s2:string;beginassign(input,'travel.in');reset(input);assign(output,'travel.out'); rewrite(output);readln(s1);readln(s2);sum:=1;for i:=1 to length(s1)-1 do beginm:=pos(s1[i],s2);if m>1 thenif s1[i+1]=s2[m-1] thensum:=sum*2; end;writeln(sum);close(input);close(output);end.2.2 产生数源程序名build.???(pas, c, cpp)可执行文件名build.exe输入文件名build.in输出文件名build.out【问题描述】给出一个整数n(n<1030)和m个变换规则(m≤20)。

Pascal_讲课稿(02)

Pascal_讲课稿(02)

Pascal语言上课笔记(二)2012-1临沂专用(勿外传)第十三节递推与递归递推和递归是编程中常用的基本算法,前面我们已经在个别程序中接触过,下面我们专门详细地研究一下递推与递归的算法。

一、递推1、递推是计算机数值计算中的一个重要算法,其思想是通过数学推导,将复杂的运算化解为若干重复的简单运算,以充分发挥计算机善长于重复处理的特点。

我们先看一道例题:例题1:切煎饼:王小二自夸刀工不错,有人放一张大的煎饼在砧板上,问他:“饼不许离开砧板,切100刀最多能分成多少块?”找规律,如下图:令q(n)为切n刀能分成的块数,从上图中可见:q(1)=1+1=2q(2)=1+1+2=4q(3)=1+1+2+3=7q(4)=1+1+2+3+4=11在切法上让每两条线都有交点,则有q(n)=q(n-1)+nq(0)=1有了递推方程,程序就很简单。

程序如下:var //递推例子程序名:0001089ditui.pasi,n:integer;knife:array[0..100] of integer;beginreadln(n);knife[0]:=1;for i:=1 to n dobeginknife[i]:=knife[i-1]+i;writeln(i:3,knife[i]:5);end;end.例题2:植树节那天,有五位同学参加了植树活动,他们完成植树的棵数都不相同。

问第一位同学植了多少棵时,他指着旁边的第二位同学说比他多植了两棵;追问第二位同学,他又说比第三位同学多植了两棵;…如此,都说比另一位同学多植两棵。

最后问到第五位同学时,他说自己植了10棵。

到底第一位同学植了多少棵树?分析:设第一位同学植树的棵数为a1,欲求a1,需从第五位同学植树的棵数a5入手,根据“多两棵”这个规律,按照一定顺序逐步进行推算:①、a5=10;②、a4=a5+2=12;③、a3=a4+2=14;④、a2=a3+2=16;⑤、a1=a2+2=18;程序如下:var //递推(植树)程序名:0001090dituizhishu.pasi,a:byte;begina:=10;for i:=1 to 4 do a:=a+2;writeln('The num of tree is : ',a);readln;end.2、递推算法以初始{起点}值为基础,用相同的运算规律,逐次重复运算,直至运算结束。

第二讲 递归与递推

第二讲  递归与递推
2008年冬令营
江 苏 省 青 少 年 信 息 学 奥 林 匹 克 夏 令 营 C 层 次 教 学
例5、由m个A,n个B组成若干个排列。从某个排列 的位置1开始数,数到任意位置时都能保证A的个数 不少于B的个数,则称该排列为合理排列。例如: 当m=2,n=2时排列有 A A B B(合理) A B A B(合 理)A B B A(不合理) B B A A(不合理) 合理排列数有2 种 输入:只有一行两个整数m,n(1≤n≤m≤12)(用 空格分隔) 输出:一个整数(所有的合理排列数) 【样例】 输入 输出 32 5
递归过程例析
先以三个盘的移动为例,看一下移动过程。
江 苏 省 青 少 年 信 息 学 奥 林 匹 克 夏 令 营 C 层 次 教 学
2008年冬令营
递归过程例析
分析 1、当n=1时,只需要移动一次A---C; 2、当n=2时,需要移动三次; A---1---B; A---2---C; B---1---C; 3、当n>=3时,先将前n-1个盘子以C为 中介移到B柱子;再将第n个盘子移到 C柱子;最后将n-1个盘子以A为中介 从B柱移到C柱。
递归关系式——如何求? 运用函数的前驱值来计算函数当前值的关系式
江 苏 省 青 少 年 信 息 学 奥 林 匹 克 夏 令 营 C 层 次 教 学
2008年冬令营
递归
例3、用递归方法求两个正整数m和n的最大公 约数。
分析:求两个数的最大公约数可以用辗转 相除法,即求m与n的最大公约数等价于求(m mod n)的值与n的最大公约数,此时的n可以当 作新的m ,而(m mod n)的值当作新的n ,所 以原问题的求解又变成求新的m与n的最大公约 数问题,继续下去,直至(m mod n)为0,最大 公约数就是最终存放在n中的值。

递归递推区别分析与例题总结

递归递推区别分析与例题总结

递归递推区别分析与例题总结递归与递推⽂章⽬录特点递归(recursive)运⾏过程中⾃我调⽤,求解过程分为回溯和递推两个过程,占⽤内存多(栈数先积累后收缩,有可能爆栈),代码简洁但低效。

尾递归和递归区别⬇function story() {从前有座⼭,⼭上有座庙,庙⾥有个⽼和尚,⼀天⽼和尚对⼩和尚讲故事:story() // 尾递归,进⼊下⼀个函数不再需要上⼀个函数的环境了,得出结果以后直接返回。

}function story() {从前有座⼭,⼭上有座庙,庙⾥有个⽼和尚,⼀天⽼和尚对⼩和尚讲故事:story(),⼩和尚听了,找了块⾖腐撞死了 // ⾮尾递归,下⼀个函数结束以后此函数还有后续,所以必须保存本⾝的环境以供处理返回值。

}尾递归省内存、⾼效(相当于(或者说递推?))Python⽆法在语⾔中实现尾递归优化(Tail Call Optimization, TCO),所以采⽤了for, while等特殊结构代替recursive的表述(优化是编译器⼲的,发现尾递归结构就给优化了)。

递推(iterative)效率⽐递归⾼,尽量递推,除⾮只能递归。

例题递推例⼦⼀般都是数学题。

重点是找递推公式(也太好偷懒了吧)平⾯分割问题直线分割平⾯(基本结论)如果当前有 n 条直线,新增加⼀条直线(第 n+1 条直线),可以多出来 n 个交点(新的直线和之前所有的直线都有交点),⽽多出来 n 个交点对应到可以多出 n+1 个平⾯(⽐如从两条线,⼜新增⼀条线时,新的线和两条线都相交,作⽤在三个区域上,对这三个区域切分,增加三个平⾯)。

也即:S n+1=S n+(n+1)=1+(n+1)(n+2)2当平⾯上已有n-1条曲线将平⾯分割成a n-1个区域后,第n-1条曲线每与曲线相交⼀次,就会增加⼀个区域,因为平⾯上已有了n-1条封闭曲线,且第n条曲线与已有的每⼀条闭曲线恰好相交于两点,且不会与任两条曲线交于同⼀点,故平⾯上⼀共增加2(n-1)个区域,加上已有的a n-1个区域,⼀共有a n-1+2(n-1)个区域。

递推与递归

递推与递归
{1,4}∪{2}∪{3}
{2,4}∪{1}∪{3}
{3,4}∪{1}∪{2}
递归的应用举例
考虑一般情况,对于任意的含有n个元素 1、数据元素可以用抽象的公式表示
再者,把n个元素放进一个集合或把n个元素放进n个集合,方案数显然都是1,即k=1或k=n时,s(n,k)=1。
a ,a ,……,a 的集合s,放入k个无标号的 【讨论1】平面分割问题
{1,2,3,4,5}的情况:
{1},{2},{3},{4},{5},{1,3},{1,4},{1,5},
{2,4},{2,5},{3,5},{1,3,5}
--->f(5)
递推
f(1)=12=1 f(2)=12+22=5 f(3)=f(2)+f(1)*32+32=23 f(4)=f(3)+f(2)*42+42=119 ……… f(n)=f(n-1)+f(n-2)*n2+n2
递推
begin readln(n,m,x,y); fillchar(f,sizeof(f),0); fillchar(g,sizeof(g),true); g[x,y]:=false; for i:=1 to 8 do g[x+dx[i],y+dy[i]]:=false;
递推
if g[0,0] then f[0,0]:=1; for i:=1 to m do
{ g[i,j] = 1 } { j>0,g[0,j] = 0 } { i>0,g[i,0] = 0 } { i>0,j>0,g[i,j] = 0 }
递推
program ex2; const
maxn=20; maxm=20; dx:array[1..8] of integer=(2,1,-1,-2,-2,-1, 1, 2); dy:array[1..8] of integer=(1,2, 2, 1,-1,-2,-2,-1); var f:array[0..maxn,0..maxm] of int64; g:array[-2..maxn+2,-2..maxm+2] of boolean; n,m,x,y:integer; i,j:integer;

递推与递归

递推与递归

递归【例】编一个函数factorial 计算阶乘n!按过去程序设计思想,该函数应该写成:int factorial ( int n ) {int i,p;p=1;;for ( i=1 ; i<=n ; i=i+1 )p=p*i;return p ;}现在换一个角度考虑问题,n! 不仅是1*2*3* ... *n还可以定义成按照该定义,n! 就是一个简单的条件语句和表达式计算,可以编出如下函数:int factorial ( int n ) {if ( n==0 )return 1;elsereturn n*factorial(n-1);}问题是该函数对不对?在函数factorial 内又调用函数factorial 本身,行吗?回答是肯定的。

首先按作用域规则,在函数factorial 内又调用函数factorial 本身是合法的;其次C 系统保证上述调用过程执行的正确性,这就是递归。

从静态行文角度看,在定义一个函数时,若在定义它的内部,又出现对它本身的调用,则称该函数是递归的,或递归定义的。

从动态执行角度看,当调用一个函数时,在进入相应函数,还没退出(返回)之前,又再一次的调用它本身,而再一次进入相应函数,则称之为递归,或称之为对相应函数的递归调用。

称递归定义的函数为递归函数。

上述函数factorial 就是递归函数。

若计算5! ,使用函数调用factorial(5) ,计算过程如图10.1 。

实际问题有许多可以递归定义,采用递归方法来编程序十分方便和简单。

【例】X 的n 次幂,可以定义为计算它的递归函数是:float power ( float x, int n ) {if ( n==0 )return 1 ;elsereturn x * power(x,n-1) ;}递归程序设计的思想体现在:用逐步求精原则,首先把一个问题分解成若干子问题,这些子问题中有问题的与原始问题具有相同的特征属性,至多不过是某些参数不同,规模比原来小了。

递归与递推——精选推荐

递归与递推——精选推荐

递归与递推递推递归递归:从已知问题的结果出发,⽤迭代表达式逐步推算出问题的开始的条件,即顺推法的逆过程,称为递归。

递推:从已知道的若⼲项出发,利⽤递推关系依次推算出后⾯的未知项的⽅法,我们称为递推算法。

递推与递归不同:递归是从未知到已知逐步接近解决问题的过程,⽽递推从已知到未知。

递推算法是⼀种⽤若⼲步可重复运算来描述复杂问题的⽅法。

递推是序列计算中的⼀种常⽤算法。

通常是通过计算前⾯的⼀些项来得出序列中的指定项的值。

递推的关系式可以暴枚找规律,也可以化繁为简,例如铺砖问题,最后⼀列砖铺与不铺,以及最后两列砖铺与不铺的情况相加即可求出关系式。

⽽关于递归,就是函数中再次调取函数,从⽽使困难的问题化为“1+1”类型简单的问题,得出结果再还原,操作过程类似于“U”型。

递归的重点是找到递归关系和递归出⼝。

……(概念太多,直接摆题)经典例题统计奇数和偶数个3内存限制:128 MiB时间限制:1000 ms标准输⼊输出题⽬类型:传统评测⽅式:⽂本⽐较题⽬描述在所有的N位正整数中,有多少个数中有偶数个数字3?⼜有多少个数有奇数个3?由于结果可能很⼤,你只需要输出这个答案对12345取余的值。

输⼊格式输⼊⼀个数N(1<=N<=1000),输⼊形式为⽂件输⼊,以读到0或⽂件末尾结束。

输出格式对于每⼀个N位正整数,输出有多少偶数个3以及多少奇数个3,中间⽤空格隔开。

样例样例输⼊2样例输出73 17数据范围与提⽰分别找出奇数偶数的递推式样例说明:在所有的2位数字,包含0个3的数有72个,包含2个3的数有1个,共73个对于⼀位数,除3外,其他全为含有偶数个三(数组元素初始化),紧接着,对于两位数,13,23,30~39(除33外)【这⾥有9个数,也可以进⾏思考】,43,53,63,73,83,93含有奇数个三,再看三位数(差不多就可以找到规律……)。

声明:a数组存储含奇数个三的个数,b数组⽤于存储偶数i的数值 1 2 3 ……a[i] 1 17 674 ……b[i] 8 73 226 ……So,a[i]=(b[i-1]+a[i-1]*9)%12345,b[i]=(a[i-1]+b[i-1]*9)%12345;#include<cstdio>using namespace std;int main(){int n,a[10005],b[10005];a[1]=1,b[1]=8;for(int i=2;i<=1001;i++){a[i]=(b[i-1]+a[i-1]*9)%12345;b[i]=(a[i-1]+b[i-1]*9)%12345;}while(scanf("%d",&n)!=EOF){if(n==0)return 0;printf("%d %d\n",b[n],a[n]);}return 0;}Hanoi塔内存限制:128 MiB时间限制:1000 ms标准输⼊输出题⽬类型:传统评测⽅式:⽂本⽐较题⽬描述问题的提出:Hanoi塔由n个⼤⼩不同的圆盘和三根⽊柱a,b,c组成。

递归与递推公式的掌握技巧

递归与递推公式的掌握技巧

递归与递推公式的掌握技巧掌握递归与递推公式的技巧在计算机科学领域中,递归和递推公式是重要的概念和工具。

递归是指在一个函数或过程内部调用自己,直到满足某个条件才返回结果。

递推公式是指通过前面的结果推导出后面的结果的公式,也称为递归公式。

递归和递推公式在算法设计、数据结构、数学等领域都得到了广泛应用。

递归和递推公式的掌握是编程和数学学习的重点之一。

在实际应用中,掌握递归和递推公式对程序的正确性、效率和可读性都是至关重要的。

本文将介绍如何掌握递归和递推公式的技巧,帮助读者更好地应用它们解决问题。

第一部分:递归的设计和实现递归的设计和实现是一项重要的技巧。

递归函数的设计和实现需要考虑以下几个方面:1.确定递归的终止条件递归的过程必须能够终止,否则会造成死循环或栈溢出等问题。

因此,在设计递归函数时必须确定递归的终止条件。

例如,计算斐波那契数列的递归函数可以定义如下:```int fibonacci(int n) {if (n <= 1) {return n;}else {return fibonacci(n - 1) + fibonacci(n - 2);}}```在这个例子中,当n小于或等于1时,递归终止,返回n的值。

如果n大于1时,递归调用fibonacci函数求解f(n-1)和f(n-2)的和。

递归终止条件的确定是函数正确实现的关键之一。

2.转化问题的规模递归通常是为了解决类似于“分而治之”的问题。

通过递归调用将原问题拆分成子问题,并在子问题得到解后合并得到原问题的解。

例如,快速排序算法就是一种递归的排序算法,它的实现如下:```void quick_sort(int arr[], int left, int right) {if (left < right) {int pivot = partition(arr, left, right);quick_sort(arr, left, pivot - 1);quick_sort(arr, pivot + 1, right);}}int partition(int arr[], int left, int right) {int pivot = arr[right];int i = left - 1;for (int j = left; j < right; j++) {if (arr[j] <= pivot) {i++;swap(&arr[i], &arr[j]);}}swap(&arr[i + 1], &arr[right]);return i + 1;}```在这个例子中,快速排序通过递归调用将原问题拆分为更小的子问题,并在子问题解决后进行合并。

递归与递推

递归与递推

1.递归与递推的区别:2.今天在学习递归和动态规划时有点迷糊了,两者无法区别,在网上差了下,总接如下:首先要清楚,递推就是迭代。

3. 1.递归其实就是利用系统堆栈,实现函数自身调用,或者是相互调用的过程.在通往边界的过程中,都会把单步地址保存下来,知道等出边界,再按照先进后出的进行运算,这正如我们装木桶一样,每一次都只能把东西方在最上面,而取得时候,先放进取的反而最后取出.递归的数据传送也类似.但是递归不能无限的进行下去,必须在一定条件下停止自身调用,因此它的边界值应是明确的.就向我们装木桶一样,我们不能总是无限制的往里装,必须在一定的时候把东取出来.比较简单的递归过程是阶乘函数,你可以去看一下.但是递归的运算方法,往往决定了它的效率很低,因为数据要不断的进栈出栈.这时递推便表现出它的作用了,所谓递推,就是免除了数据进出栈的过程.也就是说,不需要函数不断的向边界值靠拢,而直接从边界出发,直到求出函数值.比如,阶乘函数中,递归的数据流动过程如下:f(3){f(i)=f(i-1)*i}–>f(2)–>f(1)–>f(0){f(0)=1}–>f(1)–>f(2)–f(3){f(3)=6} 而递推如下:f(0)–>f(1)–>f(2)–>f(3)由此可见,递推的效率要高一些,在可能的情况下应尽量使用递推.但是递归作为比较基础的算法,它的作用不能忽视.所以,在把握这两种算法的时候应该特别注意.4. 2.递归是自顶向下逐步拓展需求,最后自下向顶运算。

即由f(n)拓展到f(1),再由f(1)逐步算回f(n)迭代是直接自下向顶运算,由f(1)算到f(n)。

2.爱拉托逊斯筛选法思想:对于不超过n的每个非负整数P,删除2*P, 3*P…,当处理完所有数之后,还没有被删除的就是素数。

int m =sqrt(double(n+0.5));for(int i =2; i <= m; i++)if(!vis[i]){for(int j = i*i; j <= n; j += i){vis[j]=1;}}#include <stdio.h>#include <string.h>#include <math.h>int vis[100];int n;int main(){scanf("%d", &n);int cnt =1;memset(vis, 0, sizeof(vis));int m =sqrt(double(n+0.5));for(int i =2; i <= m; i++)if(!vis[i]){for(int j = i*i; j <= n; j += i){vis[j]=1;//printf("%d\n", j);}}for(int i =2; i < n; i++){if(vis[i]==0){printf("%d ", i);cnt++;if(cnt %10==0)printf("\n");}}printf("\n cnt = %d\n", cnt);return0;}。

递推和递归

递推和递归

2 递推法递推法是根据具体问题,建立递推关系,再通过递推关系求解的方法。

其中递推关系是表示关于正整数参变量的一类特殊关系,它从给定的初值出发,通过这种关系一步一步地通过递推获得所需结果。

这种递推通常采用循环迭代的方法,如循环累乘、循环累加等。

[3]例如阶乘计算,假设要求5的阶乘。

C程序对应如下:#include "stdio.h"main(){ int n,s=1;for(n=1;n<=5;n + +){ s=s*n; /*1的阶乘为1,1的阶乘乘以2就是2的阶乘,2的阶乘乘以3就是3的阶乘,以此类推,直到求出5的阶乘*/}printf("5!=%d",s);}3 递归法程序调用自身的编程技巧称为递归。

一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

例如计算斐波那契(Fibonacci)数列的第n项。

斐波那契数列为:0、1、1、2、3、……,即:fib(0)=0;fib(1)=1;fib(n)=fib(n-1) fib(n-2) (当n>1时)。

用C语言写成递归函数为:int fib(int n){ if (n==0) return 0;if (n==1) return 1;if (n>1) return fib(n-1) fib(n-2); /*递归调用*/}递归算法的执行过程分递推和回归两个阶段。

在递推阶段,就是为了得到问题的解,将它推到比原问题更简单的问题求解。

例如上例中,求解fib(n),把它推到求解fib(n-1)和fib(n-2)。

也就是说,为计算fib(n),必须先计算fib(n-1)和fib(n-2),而计算fib(n-1)和fib(n-2),又必须先计算fib(n-3)和fib(n-4)。

递归算法和递推算法的原理

递归算法和递推算法的原理

递归算法和递推算法的原理-概述说明以及解释1.引言1.1 概述递归算法和递推算法是编程中常用的两种算法思想,它们都是一种问题解决的方法论。

递归算法通过将一个大问题分解为一个或多个相同的小问题来解决,而递推算法则是通过给定初始条件,通过逐步推导出后续结果来解决问题。

递归算法是一种自调用的算法,它将一个问题划分为更小规模的相同子问题,并通过调用自身来解决这些子问题。

每个子问题的解决方案被合并以形成原始问题的解决方案。

递归算法具有简洁的代码结构和易于理解的逻辑。

它在一些问题上能够提供高效的解决方案,例如树的遍历、图的搜索等。

递推算法则是从已知的初始条件开始,通过根据给定的递推公式或规则,逐步计算出后续的结果。

递推算法是一种迭代的过程,每一次迭代都会根据已知条件计算得出下一个结果。

递推算法常应用于数学问题,求解斐波那契数列、阶乘等等。

递归算法和递推算法在解决问题时的思路不同,但也存在一些相似之处。

它们都能够将大问题分解成小问题,并通过解决这些子问题来获得问题的解决方案。

而且递归算法和递推算法都有各自适用的场景和优缺点。

本文将详细介绍递归算法和递推算法的原理、应用场景以及它们的优缺点。

通过比较和分析两者的差异,帮助读者理解和选择合适的算法思想来解决问题。

1.2文章结构文章结构部分的内容可以描述文章的整体框架和各个章节的内容概要。

根据给出的目录,可以编写如下内容:文章结构:本文主要探讨递归算法和递推算法的原理及其应用场景,并对两者进行比较和结论。

文章分为四个部分,下面将对各章节的内容进行概要介绍。

第一部分:引言在引言部分,我们将对递归算法和递推算法进行简要概述,并介绍本文的结构和目的。

进一步,我们将总结递归算法和递推算法在实际问题中的应用和重要性。

第二部分:递归算法的原理在第二部分,我们将详细讨论递归算法的原理。

首先,我们会给出递归的定义和特点,探索递归的本质以及递归算法的基本原理。

其次,我们将展示递归算法在不同的应用场景中的灵活性和效果。

递归与递推的概念

递归与递推的概念

递归与递推的概念1. 嘿,亲爱的编程小伙伴们!今天咱们来聊两个特别有意思的概念:递归和递推。

别看这两个名字听着挺唬人,其实它们就像是两个性格不同的双胞胎,一个爱往回看,一个喜欢往前冲!2. 咱们先说说递归,它就像是一个特别爱回忆的人。

打个比方,你问一个递归控:"你现在有多少钱?",他不会直接告诉你,而是会说:"等我问问昨天的自己有多少钱,再加上今天赚的就知道了。

"然后他又去问昨天的自己,昨天的自己又去问前天的自己。

直到问到最初的时候才开始往回算。

3. 来看个有趣的例子: "妈妈,咱家祖上几代人都姓张啊?" "得问问你奶奶。

" "奶奶,咱家祖上几代人都姓张啊?" "得问问你太奶奶。

" 这就是典型的递归思维!4. 递归就像是套娃,一个套一个,一层套一层。

每次都要往更小的问题钻,钻到最底层,再一层层往回冒。

有时候可把程序员愁坏了,因为套得太多容易把电脑内存给撑爆!5. 再说说递推,这家伙可就直接多了,是个实在人。

它不会像递归那样绕来绕去,而是踏踏实实地一步一步往前走。

就像盖房子,先打地基,再一层层往上盖,每一步都基于前面的结果。

6. 举个生动的例子: "小明,你知道你的零花钱是怎么算的吗?" "知道啊!每天比前一天多一块钱,昨天是5块,今天就是6块,明天就是7块。

" 这就是标准的递推思维!7. 递推特别适合那种知道起点,要算后面的值的问题。

比如兔子生兔子的问题,知道一开始有一对兔子,每个月都按固定规律生,要算第十个月有多少对,递推就特别好使。

8. 有意思的是,很多问题既可以用递归解决,也可以用递推解决。

就像爬楼梯,你可以从上往下想递归,也可以从下往上算递推。

选哪个全看你喜欢哪种思维方式!9. 不过要说哪个更省电脑资源,那肯定是递推了。

递归虽然写起来简单,但是总要存储很多中间状态,就像是搬家时非要把路上经过的每个地方都记下来一样,太费劲了!10. 递推就实在多了,只记住需要用到的状态,其他的都扔掉。

递推和递归

递推和递归

递推和递归
递推和递归都是计算机科学中常用的算法思想。

递推是一种通过已知值求解未知值的算法,通常是从已知值开始,根据已知值和某种递推公式,依次计算出未知值。

递推算法通常使用循环结构实现,适用于求解数列、斐波那契数列等问题。

例如,斐波那契数列的递推公式为:F(n) = F(n-1) + F(n-2),其中F(0)=0,F(1)=1。

通过递推公式和已知值F(0) 和F(1),可以依次计算出F(2)、F(3)、F(4) 等未知值。

递归是一种通过调用自身函数来解决问题的算法,通常用于解决复杂的问题,例如树的遍历、图的搜索等问题。

递归算法通常使用函数的递归调用来实现,适用于求解具有递归结构的问题。

例如,计算n! 的递归函数可以定义为:factorial(n) = n * factorial(n-1),其中factorial(0)=1。

通过递归调用factorial 函数,可以依次计算出n! 的值。

需要注意的是,递推和递归都需要考虑边界条件和递归深度等问题,否则可能会导致程序出现栈溢出等错误。

pascal-递归(理解).

pascal-递归(理解).

7.6 函数的递归调用在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。

C语言的特点之一就在于允许函数的递归调用。

例如:int f(int x){int y,z;z=f(y);return(2*z);}在调用函数f的过程中,又要调用f函数,这是直接调用本函数,见图8.9。

下面是间接调用本函数。

图 8.9 图8.10在调用f1函数过程中要调用f2函数,而在调用f2函数过程中又要调用f1函数,见图8.10。

从图上可以看到,这两种递归调用都是无终止的自身调用。

显然,程序中不应出现这种无终止的递归调用,而只应出现有限次数的、有终止的递归调用,这可以用if语句来控制,只有在某一条件成立时才继续执行递归调用,否则就不再继续。

关于递归的概念,有些初学者感到不好理解,下面用一个通俗的例子来说明。

例8.7 有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。

问第4个人岁数,他说比第3个人大2岁。

问第3个人,又说比第2个人大2岁。

问第2个人,说比第1个人大2岁。

最后问第1个人,他说是10岁。

请问第5个人多大。

显然,这是一个递归问题。

要求第5个人的年龄,就必须先知道第4个人的年龄,而第4个人的年龄也不知道,要求第4个人的年龄必须先知道第3个人的年龄,而第3个人的年龄又取决于第2个人的年龄,第2个人的年龄取决于第1个人的年龄。

而且每一个人的年龄都比其前1个人的年龄大2。

即 age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10可以用式子表述如下:age(n)=10 (n=1)age(n-1)+2 (n>1)可以看到,当n>1时,求第n个人的年龄的公式是相同的。

因此可以用一个函数表示上述关系。

图8.11表示求第5个人年龄的过程。

图8.11从图可知,求解可分成两个阶段:第一阶段是“回推”,即将第n个人的年龄表示为第(n-1)个人年龄的函数,而第(n-1)个人的年龄仍然不知道,还要“回推”到第(n-2)个人的年龄……直到第1个人年龄。

递推与递归

递推与递归

递推与递归三、递推法递推法是利用问题本身所具有的一种递推关系求问题解的一种方法。

设要求问题规模为N的解,当N=1时,解或为已知,或能非常方便地得到解。

能采用递推法构造算法的问题有重要的递推性质,即当得到问题规模为i-1的解后,由问题的递推性质,能从已求得的规模为1,2,…,i-1的一系列解,构造出问题规模为i的解。

这样,程序可从i=0或i=1出发,重复地,由已知至i-1规模的解,通过递推,获得规模为i的解,直至得到规模为N的解。

【问题】阶乘计算问题描述:编写程序,对给定的n(n≦100),计算并输出k的阶乘k!(k=1,2,…,n)的全部有效数字。

由于要求的整数可能大大超出一般整数的位数,程序用一维数组存储长整数,存储长整数数组的每个元素只存储长整数的一位数字。

如有m位整数N用数组a[ ]存储:N=a[m]×10m-1+a[m-1]×10m-2+ … +a[2]×101+a[1]×100并用a[0]存储长整数N的位数m,即a[0]=m。

按上述约定,数组的每个元素存储k的阶乘k!的一位数字,并从低位到高位依次存于数组的第二个元素、第三个元素……。

例如,5!=120,在数组中的存储形式为:3 0 2 1 ……首元素3表示长整数是一个3位数,接着是低位到高位依次是0、2、1,表示成整数120。

计算阶乘k!可采用对已求得的阶乘(k-1)!连续累加k-1次后求得。

例如,已知4!=24,计算5!,可对原来的24累加4次24后得到120。

细节见以下程序。

# include <stdio.h># include <stdlib.h># define MAXN 1000void pnext(int a[ ],int k){int *b,m=a[0], i, j, r ,carry;b=(int * ) malloc(sizeof(int)* (m+1));for ( i=1;i<=m;i++) b[i]=a[i];for ( j=1;j<=k;j++){for ( carry=0,i=1;i<=m;i++){r=a[i]+b[i]+carry;a[i]=r%10;carry=r/10;}if (carry) a[++m]=carry;}free(b);a[0]=m;}void write(int *a,int k){ int i;printf(“%4d!=”,k);for (i=a[0];i>0;i--)printf(“%d”,a[i]);printf(“\n\n”);}void main(){int a[MAXN],n,k;printf(“Enter the number n: “);scanf(“%d”,&n);a[0]=1;a[1]=1;write(a,1);for (k=2;k<=n;k++){pnext(a,k);write(a,k);getchar();}}四、递归递归是设计和描述算法的一种有力的工具,由于它在复杂算法的描述中被经常采用,为此在进一步介绍其他算法设计方法之前先讨论它。

递归和递推(end)

递归和递推(end)
方法一:穷举 方法二:二分查找
分析
二分查找的基本思想:首先将结点按排序,其次将查 找值与中间位置的值比较,相等,查找成功;不等,则中 间数据大于或小于查找值,无论怎样查找将在一半的 数据中查找。
例如在有序数列15 数x=19
20 26 31
40中查找
第一次:left=1 right=5 mid=3 x<a[mid]
var m:longint;
writeln(m); end;
利用实参实现!
函数与过程区别
1.声明方式不同 2.返回值的方式不同,函数必须 要对函数名进行赋值,过程则 不必。
讨论:函数与过程的选择?
例3
function fac(x:integer):longint; begin if x=1 then fac:=1 else fac:=fac(x-1)*x; end; 问:此函数合法吗? 实现什么功能?如何实现?
递归的概念
• 递归就是函数或过程自己直接或间 接调用自己! • 两个条件: 1.递归式(递归关系); 2.边界条件。 递归表达式才是解题的关键!
function fac(x:integer):longint; begin if x=1 then fac:=1 else fac:=fac(x-1)*x; end;
迭代
反向迭代
S:=__④____;
N:=0;
Repeat
N:=n+1;s:=n;
For i:=____①___do
For i:=___⑤___ do
S:=___⑥______; Writeln(s);
s:=__②___;
Until s=__③____; Writeln(n);
(2)猴子吃桃。有一群猴子摘来了一批桃子,猴王 规定每天只准吃一半加一只(即第二天吃剩下的一半 加一只,以此类推),第九天正好吃完,问猴子们摘 来了多少桃子?

Pascal递归算法

Pascal递归算法

第七讲递归算法【递归的定义】为了描述问题的某一状态,必须用到它的上一状态,而描述上一状态,又必须用到它的上一状态……这种用自已来定义自己的方法,称为递归定义。

例如:定义函数f(n)为:则当n<>0时,须用f(n-1)来定义f(n),用f(n-1-1)来定义f(n-1)……当n=0时,f(n)=1。

由上例我们可看出,递归定义有两个要素:(1)递归边界条件。

也就是所描述问题的最简单情况,它本身不再使用递归的定义。

如上例,当n=0时,f(n)=1,不使用f(n-1)来定义。

(2)递归定义:使问题向边界条件转化的规则。

递归定义必须能使问题越来越简单。

如上例:f(n)由f(n-1)定义,越来越靠近f(0),也即边界条件。

最简单的情况是f(0)=1。

递归算法的效率往往很低, 费时和费内存空间. 但是递归也有其长处, 它能使一个蕴含递归关系且结构复杂的程序简介精炼, 增加可读性. 特别是在难于找到从边界到解的全过程的情况下, 如果把问题推进一步没其结果仍维持原问题的关系, 则采用递归算法编程比较合适.递归按其调用方式分为:1. 直接递归, 递归过程P直接自己调用自己;2. 间接递归, 即P包含另一过程D, 而D又调用P。

递归算法适用的一般场合为:1. 数据的定义形式按递归定义.如裴波那契数列的定义: f(n)=f(n-1)+f(n-2); f(0)=1; f(1)=2.对应的递归程序为:Function fib(n : integer) : integer;Beginif n = 0 then fib := 1 { 递归边界 }else if n = 1 then fib := 2 { 递归边界 }else fib := fib(n-2) + fib(n-1) { 递归 }End;这类递归问题可转化为递推算法, 递归边界作为递推的边界条件.2. 数据之间的关系(即数据结构)按递归定义. 如树的遍历, 图的搜索等.3. 问题解法按递归算法实现. 例如回溯法等.【举例】例1:楼梯有n阶台阶,上楼可以一步上1阶,也可以一步上2阶,编一程序计算共有多少种不同的〖问题分析〗:设n阶台阶的走法数为f(n),显然有:例2:求m与n的最大公约数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第二章递归与递推2.1 遍历问题我们都很熟悉二叉树的前序、中序、后序遍历,在数据结构中常提出这样的问题:已知一棵二叉树的前序和中序遍历,求它的后序遍历,相应的,已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。

然而给定一棵二叉树的前序和后序遍历,你却不能确定其中序遍历序列,考虑如下图中的几棵二叉树:a a a a/ / \ \b b b b/ \ / \c c c c所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同。

【输入】输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。

【输出】输出可能的中序遍历序列的总数,结果不超过长整型数。

【样例】trave1.in trave1.outabc 4bca【算法分析】根据二叉树先序遍历和后序遍历的特点,可以知道,先序遍历的第一个结点是后序遍历的最后一个结点,对于中序遍历来说却是中间的一个结点,这里所说的中间也只是相对而言的中间。

如果一棵二叉树的根结点没有左子树,那么先序遍历的第一个结点也是中序遍历的第一个结点,如果一棵二叉树的根结点没有右子树,那么先序遍历的第一个结点是中序遍历的最后一个结点。

我们这里还认为就是中序遍历的中间结点,上面两种情况只是特殊的情况。

设二叉树的结点总数为n(对于输入的字符串来说是它的长度),对于先序遍历的结果,第一个结点为根结点,从第二个结点到最后一个结点分为n种情况:根结点的左子树结点个数为n-1,右子树结点的个数为0;根结点的左子树结点个数为n-2,右子树结点的个数为1;……根结点的左子树结点个数为n-i,右子树结点的个数为i-1;{0<=i<=n-1);……根结点的左子树结点个数为0,右子树结点的个数为n-1。

根据这n种情况,分别将二叉树拆分为左子树和右子树,左子树结点个数为n-i,右子树结点的个数为i-l(0<=i<=n-1),先序遍历的结果是从第二个结点(字符)开始取,而后序遍历的结果里是从第1个结点字符开始取。

也就是说对于每一种情况,分两步处理:第一步在先序遍历和后序遍历的结果里取左子树,看是否符合规则,统计这部分可能有的中序遍历的结果数目;第二步在先序遍历和后序遍历的结果里取右子树,看是否符合规则,统计这部分可能有的中序遍历的结果数目。

这两步都递归调用了统计过程,不再递归调用的条件就是当统计的是空树或只有一个结点的树,这时返回的值是可能有的中序遍历结果数目。

结合“分类相加原理”和“分步相乘原理”,可以得到下面的递归函数:【思考与提高】上面的算法通过递归,结合统计的基本原理“分步相乘,分类相加”,从而统计出所有可能解的个数,如果输入的两个字符串没有解,上述算法同样能得到结果。

在肯定有解的情况下,上述算法最终可以递归调用到0、1个结点,如果有多组解,那么调用到两个结点时,如先序为ab、后序为ba,此时有可能有如下两种结构:a a/ \b b这两种结构的中序遍历结果分别为:ba、ab,有两种。

根据分步相乘的原理,对比两个字符串,每出现一次如上的情况,可能有的结构数目(结构不同,中序遍历结果也不同,因此可能有的二叉树结构的数目就是可能有的中序遍历结果数目)就乘以2一次,最终得到总的数目。

这也可以理解为一种递推的方法。

从这里可以看到,在肯定有解的情况下,给定先序遍历的结果和后序遍历的结果,可能有2n种可能的结构,也就是中序遍历可能得到2n种不同的结果,其中n>=0。

那么这里的n最大可能是多少呢?可以证明n的最大值为字符串的长度加1整除2。

递推的程序如下:2.2 产生数【问题描述】给出一个整数n(n<1030)和m个变换规则(m≤20)。

约定:一个数字可以变换成另一个数字,规则的右部不能为零,即零不能由另一个数字变换而成。

而这里所说的一个数字就是指一个一位数。

现在给出一个整数n和m个规则,要你求出对n的每一位数字经过任意次的变换(0次或多次),能产生出多少个不同的整数。

【输入】共m+2行,第一行是一个不超过30位的整数n,第2行是一个正整数m,接下来的m 行是m个变换规则,每一规则是两个数字x、y,中间用一个空格间隔,表示x可以变换成y。

【输出】仅一行,表示可以产生的不同整数的个数。

【样例】build.in build.out1 2 3 621 22 3【算法分析】如果本题用搜索,搜索的范围会很大(因为n可能有30位!),显然无法在规定的时间内出解。

而我们注意到本题只需计数而不需要求出具体方案,所以我们稍加分析就会发现,可以用乘法原理直接进行计数。

设F[i]表示从数字i出发可以变换成的数字个数(这里的变换可以是直接变换,也可以是间接变换,比如样例中的1可以变换成2,而2又可以变换成3,所以1也可以变换成3;另外自己本身不变换也是一种情况)。

那么对于一个长度为m位的整数a,根据乘法原理,能产生的不同的整数的个数为:F[a[1]]*F[a[2]]*F[a[3]]*…*F[a[m]]。

下面的问题是如何求F[i]呢?由于这些变换规则都是反映的数字与数字之间的关系,所以定义一个布尔型的二维数组g[0..9,0..9]来表示每对数字之间是否可以变换,初始时都为False;根据输入的数据,如果数字i能直接变换成数字j,那么g[i,j]置为True,这是通过一次变换就能得到的;接下来考虑那些间接变换可得到的数字对,很明显:如果i可以变为k,k又可以变为j,那么i就可以变为j,即:for k:=0 to 9 dofor i:=0 to 9 dofor j:=0 to 9 dog[i,j]=g[i,j]or(g[i,k] and g[k,j]);最后还要注意,当n很大时,解的个数很大,所以要用高精度运算。

2.3 出栈序列统计【问题描述】栈是常用的一种数据结构,有n个元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。

你已经知道栈的操作有两种:push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。

现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。

请你编程求出对于给定的n,计算并输出由操作数序列1,2,…,n,经过一系列操作可能得到的输出序列总数。

【输入】【输出】就一个数n(1≤n≤1000)。

一个数,即可能输出序列的总数目。

【样例】stack.in stack.out3 5【算法分析】在第一章练习里,我们通过回溯的方法计算并输出不同的出栈序列,这里只要求输出不同的出栈序列总数目,所以我们希望能找出相应的递推公式进行处理。

从排列组合的数学知识可以对此类问题加以解决。

我们先对n个元素在出栈前可能的位置进行分析,它们有n个等待进栈的位置,全部进栈后在栈里也占n个位置,也就是说n个元素在出栈前最多可能分布在2*n位置上。

出栈序列其实是从这2n个位置上选择n个位置进行组合,根据组合的原理,从2n个位置选n个,有C(2n,n)个。

但是这里不同的是有许多情况是重复的,每次始终有n个连续的空位置,n个连续的空位置在2n个位置里有n+1种,所以重复了n+1次。

所以出栈序列的种类数目为:C(2n,n)/(n+1)=2n*(2n-1)*(2n-2)…*(n+1)/n!/(n+1)=2n*(2n-1)*(2n-2)*…*(n+2)/n!。

考虑到这个数据可能比较大,所以用高精度运算来计算这个结果。

本题实际是一个经典的Catalan数模型。

有关Catalan数的详细解释请参考《组合数学》等书。

【思考与提高】我们知道,在某个状态下,所能做的操作(移动方法)无非有两种:(1)将右方的等待进栈的第一个元素进栈;(2)将栈顶的元素出栈,进入左边的出栈序列。

设此时右方、栈、左方的元素个数分别为a,b,c。

我们就能用(a,b,c)表示出当前的状态。

显然n=a+b+c,则c=n-a-b。

即已知a和b,c就被确定,所以我们可以用(a,b)来作为状态的表示方法。

则起始状态为(n,0),目标状态为(0,0)。

又由上面的两种移动方法,我们可类似的得到两种状态转移方式:再设f (a,b )为从状态(a,b )通过移动火车变为状态(0,0)的所有移动方法。

类似于动态规划的状态转移方程,我们可写出以下递归式:⎪⎩⎪⎨⎧=-=>+->>-++-=≤+)(此时只能做出栈操作)(此时只能做进栈操作)0()1,()0,0()1,1()0,0()1,()1,1()(),(a b a f b a b a f b a b a f b a f n b a b a f边界值:f (0,0)=1。

有了这个递归公式后,再写程序就比较简单了,请读者自己写出递归程序。

2.4 计数器【问题描述】一本书的页数为N,页码从1开始编起,请你求出全部页码中,用了多少个0,1,2,…,9。

其中—个页码不含多余的0,如N=1234时第5页不是0005,只是5。

【输入】一个正整数N(N≤109),表示总的页码。

【输出】共十行:第k行为数字k-1的个数。

【样例】count.in count.out11 1411111111【算法分析】本题可以用一个循环从1到n,将其拆为一位一位的数字,并加到相应的变量里,如拆下来是1,则count[1]增加1。

这种方法最简单,但当n比较大时,程序运行的时间比较长。

这种方法的基本程序段如下:for i:=1 to n do beginj:=i;while j>0 do begincount[j mod 10]:=count[j mod 10]+1;j:=j div 10;end;end;当n是整型数据时,程序执行的时间不会太长。

而n是长整型范围,就以n是一个9位数为例,当i执行到8位数时,每拆分一次内循环要执行8次,执行完8位数累计内循环执行的次数为:9*1+90*2+900*3+9000*4+90000*5+900000*6+9000000*7+90000000*8时间上让人不能忍受。

可以从连续数字本身的规律出发来进行统计,这样速度比较快,先不考虑多余的0的情况,假设从0000~9999,这一万个连续的数,0到9用到的次数都是相同的,一万个四位数,0到9这十个数字共用了40000次,每个数字使用了4000次。

进一步推广,考虑所有的n位数情况,从n个0到n个9,共10n个n位数,0到9十个数字平均使用,每个数字共用了n*10n-1次。

有了这样的规律后,可以从高位向低位进行统计,最后再减去多余的0的个数。

以n=3657为例:(用count数组来存放0到9各个数字的使用次数)最高位(千位)为3,从0千、1千到2千,000~999重复了3次,每一次从000到999,每个基本数字都使用了3*102=300次,重复3次,所以count[0]~count[9]各增加3*300;另外最高位的0到2作为千位又重复了1000次,count[0]~count[2]各增加1000,3作为千位用了657次(=n mod 100),因此count[3]增加657;接下来对百位6再进行类似的处理,0到9在个位和十位平均重复使用6*20次,所以count[0]~count[9]先各增加6*20,0到5作为百位重复使用了100次,所以count[0]~count[5]再各增加100,6作为百位在这里重复用了57次(=n mod 100);因此count[6]增加57;对十位和个位也进行相同的处理,得出count[0]~count[9]的值;最后再减去多算的0的个数。

相关文档
最新文档