递归算法详解
递归算法及经典例题详解

递归算法及经典例题详解
1.什么是递归
递归简单来说就是在运行过程中不断调用自己,直到碰到终止条件,返回结果的过程。
递归可以看作两个过程,分别是递和归。
递就是原问题把要计算的结果传给子问题;归则是子问题求出结果后,把结果层层返回原问题的过程。
下面设一个需要经过三次递归的问题,为大家详细看一下递归的过程:当然,现实中我们遇到递归问题是不会按照图中一样一步一步想下来,主要还是要掌握递归的思想,找到每个问题中的规律。
2.什么时候使用递归
递归算法无外乎就是以下三点:1.大问题可以拆分为若干小问题2.原问题与子问题除数据规模不同,求解思路完全相同3.存在递归终止条件
而在实际面对递归问题时,我们还需要考虑第四点:
当不满足终止条件时,要如何缩小函数值并让其进入
下一层循环中
3.递归的实际运用(阶层计算)
了解了大概的思路,现在就要开始实战了。
下面我们来看一道经典例题:
求N的阶层。
首先按照思路分析是否可以使用递归算法:
1.N!可以拆分为(N-1)!*N
2.(N-1)!与N!只有数字规模不同,求解思路相同
3.当N=1时,结果为1,递归终止
满足条件,可以递归:
publicstaticintFactorial(int num){if(num==1){return num;}return num*Factorial(num-1);}
而最后的return,便是第四步,缩小参数num的值,让递归进入下一层。
一般来说,第四步往往是最难的,需要弄清该如何缩
小范围,如何操作返回的数值,这一步只能通过不断
地练习提高了(当然如果你知道问题的数学规律也是
可以试出来的)。
简述递归算法的执行过程

简述递归算法的执行过程摘要:1.递归算法的定义和基本原理2.递归算法的执行过程3.递归算法的应用实例4.递归算法的时间复杂度和优化方法5.总结正文:递归算法是一种自调用算法,通过将问题分解为更小的子问题来解决问题。
它在计算机科学和数学领域中广泛应用,具有可读性和实用性。
下面详细介绍递归算法的执行过程、应用实例、时间复杂度和优化方法。
一、递归算法的定义和基本原理递归算法是一种算法,它通过将问题分解为更小的子问题来解决问题。
这些子问题与原始问题具有相似的特征,从而使得算法可以通过重复调用自身来解决这些子问题。
在递归算法中,有一个基本情况(base case)和递归情况(recursive case)。
基本情况是问题规模足够小,可以直接给出答案的情况;递归情况则是将问题分解为更小的子问题,并重复调用算法本身来解决这些子问题。
二、递归算法的执行过程1.初始化:定义问题的初始条件,通常是基本情况。
2.判断基本情况:如果问题规模足够小,直接给出答案。
3.划分问题:将问题分解为更小的子问题,并确保这些子问题与原始问题具有相似的特征。
4.递归调用:将子问题传递给算法本身,重复执行步骤1-3,直到基本情况出现。
5.合并结果:将递归调用返回的结果合并,得到最终答案。
三、递归算法的应用实例1.计算阶乘:递归算法可以用于计算一个正整数的阶乘。
例如,计算5的阶乘:```def factorial(n):if n == 0:return 1else:return n * factorial(n-1)```2.计算Fibonacci 数列:递归算法可以用于计算Fibonacci 数列。
例如,计算第n个Fibonacci 数:```def fibonacci(n):if n == 0:return 0elif n == 1:return 1else:return fibonacci(n-1) + fibonacci(n-2)```四、递归算法的时间复杂度和优化方法1.时间复杂度:递归算法的时间复杂度通常为O(2^n),其中n为问题的规模。
爬楼梯方法递归算法详解

爬楼梯方法递归算法详解宝子!今天咱们来唠唠爬楼梯方法里的递归算法,可有趣啦。
你想啊,假如你要爬楼梯,每次只能走1步或者2步。
那要是只有1级楼梯,那很简单呀,就只有1种走法,直接一步就上去啦。
要是有2级楼梯呢,你可以一次走2步,或者分两次每次走1步,这就有2种走法。
那要是楼梯级数多了呢?比如说有n级楼梯。
我们就可以用递归的思想来看这个问题哦。
啥是递归呢?简单说就是自己调用自己。
对于n级楼梯的走法数量,其实就等于先走1步后剩下的n - 1级楼梯的走法数量,加上先走2步后剩下的n - 2级楼梯的走法数量。
就好像你站在楼梯口,你有两种选择嘛,走1步或者走2步,这两种选择后面的走法数量加起来就是总的走法数量啦。
我们可以把这个写成一个数学表达式一样的东西哦。
假设f(n)表示n级楼梯的走法数量,那就有f(n)=f(n - 1)+f(n - 2)。
这是不是有点像斐波那契数列呀?对啦,它们很相似呢。
但是呢,这里我们得有个基础情况,就像刚刚说的,当n = 1的时候,f(1)=1,当n = 2的时候,f(2)=2。
要是没有这个基础情况,这个递归就没完没了啦,就像你在一个圈里一直转,不知道啥时候停。
比如说现在有3级楼梯,那f(3)就等于f(2)+f(1),也就是2 + 1 = 3种走法。
再要是4级楼梯呢,f(4)就等于f(3)+f(2),根据前面算出来的,f(3)=3,f(2)=2,那f(4)=3+2 = 5种走法。
递归算法就像是一个聪明的小助手,它能把复杂的爬楼梯走法数量的计算,分解成简单的基础情况和重复的小问题。
不过呢,递归算法有时候也会有点小脾气哦,要是楼梯级数太多了,它可能会算得比较慢,因为它要不断地调用自己。
但不管怎么说,这个递归算法来解决爬楼梯的走法数量问题,真的是超级巧妙呢。
宝子,现在是不是对这个递归算法有点感觉啦? 。
递归算法知识点总结

递归算法知识点总结一、基本概念递归算法的基本概念是基于递归函数的思想。
递归函数是一个调用自身的函数。
递归算法通常可以分为两种类型:简单递归和复杂递归。
简单递归是指在递归函数中直接调用自身,而复杂递归则是指在递归函数中可能会有多个递归调用。
递归算法通常用于解决可以分解为若干子问题的问题,这种方法通常可以更加简洁地解决问题,但同时也可能会带来一些计算复杂度的问题。
递归算法的设计通常包括以下几个步骤:1. 确定基本情况:在设计递归函数时,通常需要确定一个或多个基本情况。
基本情况通常是指在递归函数中不需要再次调用自身的情况。
2. 确定递归情况:在设计递归函数时,需要确定一个或多个递归情况。
递归情况通常是指在递归函数中需要调用自身的情况。
3. 确定递归方式:当确定了递归函数的基本情况和递归情况之后,就需要确定递归函数的调用方式。
通常有两种方式:直接递归和间接递归。
4. 编写递归函数:根据确定的基本情况、递归情况和递归方式,编写递归函数。
5. 测试递归函数:编写递归函数后,需要对递归函数进行测试,确保递归函数能够正确地解决问题。
二、递归算法的原理递归算法的原理是基于递归函数的调用。
当一个递归函数被调用时,它会将自身的执行环境保存到栈中,并且在栈中分配一些空间。
在递归函数中,如果有一些局部变量,这些变量会在栈中分配空间。
随着递归函数的深入调用,栈中的空间也会不断增加。
在递归函数的执行过程中,通常需要考虑递归栈的压栈和出栈操作。
在递归函数被调用时,会执行一些初始化操作,并将递归参数保存到栈中。
在递归函数中,如果遇到递归情况,会再次调用自身,并且将自身的执行环境保存到栈中。
在递归函数的执行过程中,如果遇到基本情况,就会结束当前递归调用,并且从栈中释放空间。
递归算法的原理是基于递归函数的深度调用的。
当递归函数被调用时,会执行一些初始化过程,并将递归参数保存到栈中。
当递归函数执行完毕后,会从栈中释放空间。
在递归函数的执行过程中,栈中的空间会不断增加和释放。
递归算法详解完整版

递归算法详解完整版递归算法是一种重要的算法思想,在问题解决中起到了很大的作用。
它通过将一个大问题划分为相同或类似的小问题,并将小问题的解合并起来从而得到大问题的解。
下面我们将详细介绍递归算法的定义、基本原理以及其应用。
首先,我们来定义递归算法。
递归算法是一种通过调用自身解决问题的算法。
它通常包括两个部分:基础案例和递归步骤。
基础案例是指问题可以被直接解决的边界情况,而递归步骤是指将大问题划分为较小问题并通过递归调用自身解决。
递归算法的基本原理是"自顶向下"的思维方式。
即从大问题出发,不断将问题划分为较小的子问题,并解决子问题,直到达到基础案例。
然后将子问题的解合并起来,得到原始问题的解。
递归算法的最大特点是简洁而优雅。
通过将复杂问题分解为简单问题的解决方式,可以大大减少代码的复杂程度,提高程序的效率和可读性。
但是递归算法也有一些缺点,包括递归深度的限制和复杂度的不确定性。
过深的递归调用可能导致栈溢出,而不合理的递归步骤可能导致复杂度过高。
递归算法有许多应用场景,我们来介绍其中一些典型的应用。
1.阶乘问题:计算一个数的阶乘。
递归算法可以通过将问题划分为更小的子问题来解决。
例如,n的阶乘可以定义为n乘以(n-1)的阶乘。
当n 等于1时,我们可以直接返回1作为基础案例。
代码如下:```int factorial(int n)if (n == 1)return 1;}return n * factorial(n - 1);```2.斐波那契数列问题:求斐波那契数列中第n个数的值。
斐波那契数列的定义是前两个数为1,然后从第三个数开始,每个数都是前两个数的和。
递归算法可以通过将问题划分为两个子问题来解决。
当n等于1或2时,直接返回1作为基础案例。
代码如下:```int fibonacci(int n)if (n == 1 , n == 2)return 1;}return fibonacci(n - 1) + fibonacci(n - 2);```3.二叉树问题:对于给定的二叉树,递归算法可以通过递归调用左子树和右子树的解来解决。
6种基本算法 递归

6种基本算法递归递归是一种重要的算法思想,它在计算机科学中得到广泛应用。
本文将介绍六种基本的递归算法,并对其原理和应用进行讲解。
一、递归的基本概念递归是指一个函数在其定义中调用自身的过程。
递归算法通过将一个大问题划分为一个或多个相同或相似的子问题,然后通过解决子问题来解决原始问题。
递归算法具有简洁、优雅以及可读性强的特点,但同时也需要注意递归的停止条件,以避免无限递归的发生。
二、阶乘算法阶乘算法是递归算法中最经典的例子之一。
它的定义如下:```n! = n * (n-1) * (n-2) * ... * 1```其中,n为一个非负整数。
阶乘算法可以通过递归的方式实现,即:```fact(n) = n * fact(n-1)```其中,停止条件为`n=0`时,返回1。
三、斐波那契数列算法斐波那契数列是一个无限序列,其定义如下:```F(0) = 0F(1) = 1F(n) = F(n-1) + F(n-2) (n>1)```斐波那契数列算法可以通过递归的方式实现,即:```fib(n) = fib(n-1) + fib(n-2)```其中,停止条件为`n=0`或`n=1`时,返回相应的值。
四、二分查找算法二分查找算法是一种高效的查找算法,它的基本原理是将已排序的数组分成两部分,然后判断目标值在哪一部分,并继续在该部分中进行查找,直到找到目标值或者查找范围为空。
二分查找算法可以通过递归的方式实现,即:```binarySearch(arr, target, start, end) = binarySearch(arr, target, start, mid-1) (target < arr[mid])= binarySearch(arr, target, mid+1, end) (target > arr[mid])= mid (target = arr[mid])```其中,`arr`为已排序的数组,`target`为目标值,`start`和`end`为查找范围的起始和结束位置。
递归算法 递推公式求解

递归算法递推公式求解递归算法是一种自我调用的算法,它通过不断将问题分解为更小的子问题来求解问题。
递归算法的核心是递推公式,也称为递归式,它描述了如何将问题分解为子问题,并如何从子问题的解中得到原问题的解。
递推公式通常具有以下形式:T(n) = aT(n/b) + f(n)其中,T(n) 表示问题规模为n 时的时间复杂度,a 表示每次递归调用的次数,b 表示每次递归调用后问题规模缩小的比例,f(n) 表示除了递归调用外的其他操作的时间复杂度。
为了求解递推公式,我们可以使用以下方法:1.迭代法:通过迭代递推公式的方式逐步计算出T(n) 的值。
这种方法比较直观,但对于较大的n 值,迭代次数可能非常多,计算量也会非常大。
2.替换法:通过猜测T(n) 的形式,并将其代入递推公式中进行验证。
如果猜测正确,则可以得到T(n) 的解。
这种方法需要对问题有一定的了解和猜测能力。
3.大师定理:大师定理是一种求解递推公式的通用方法。
它可以根据递推公式的形式,直接给出T(n) 的时间复杂度。
大师定理有多种形式,其中最常用的是以下三种:a. 如果f(n) = O(n^c),其中c < log_b(a),则T(n) = O(n^log_b(a))。
b. 如果f(n) = O(n^c),其中c = log_b(a),则T(n) = O(n^c * log_n)。
c. 如果f(n) = O(n^c),其中c > log_b(a),且对于所有足够大的n,有af(n/b) <= f(n),则T(n) = O(f(n))。
需要注意的是,大师定理只是一种求解递推公式的工具,它并不能解决所有类型的递推公式。
在实际应用中,我们需要根据具体问题选择合适的求解方法。
排列组合递归算法

排列组合递归算法是一种基于递归思想的算法,用于解决与排列和组合相关的问题。
下面是排列组合递归算法的详细介绍:
基本概念:
排列(Permutation):从n个不同元素中取出m(m ≤n)个不同元素按照一定的顺序排成一列,称为从n个元素中取出m个元素的一个排列,所有排列的个数记为P(n,m)。
组合(Combination):从n个不同元素中取出m(m ≤n)个不同元素按照一定的顺序排成一列,不考虑排列的顺序,称为从n个元素中取出m个元素的一个组合,所有组合的个数记为C(n,m)。
递归的基本思想:
递归算法的基本思想是将一个复杂的问题分解为若干个简单的问题,然后将这些简单问题的解组合起来得到原问题的解。
在排列组合问题中,可以将一个大问题分解为若干个小问题,例如:从n个元素中取出m个元素的排列/组合问题可以分解为从剩余元素中继续取下一个元素的问题。
递归公式:
排列的递归公式:P(n,m) = n * P(n-1,m-1) + P(n-1,m)
组合的递归公式:C(n,m) = P(n,m) / P(m,m) = (n * P(n-1,m-1) + P(n-1,m)) / P(m,m)
应用示例:
使用排列组合递归算法可以解决很多与排列和组合相关的问题,例如:给定一个数组,求数组中所有元素的排列/组合数、给定一个集合,求集合的所有子集等。
注意事项:
在使用递归算法时需要注意避免出现无限递归的情况,需要对递归终止条件进行正确的设置。
另外,由于递归算法会涉及到大量的重复计算,因此在处理大规模数据时可能会效率较低,可以考虑使用动态规划等优化方法来提高算法的效率。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
递归算法详解C通过运行时堆栈支持递归函数的实现。
递归函数就是直接或间接调用自身的函数。
许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的《C语言程序设计》一书中就是从阶乘的计算开始的函数递归。
导致读过这本经书的同学们,看到阶乘计算第一个想法就是递归。
但是在阶乘的计算里,递归并没有提供任何优越之处。
在菲波那契数列中,它的效率更是低的非常恐怖。
这里有一个简单的程序,可用于说明递归。
程序的目的是把一个整数从二进制形式转换为可打印的字符形式。
例如:给出一个值4267,我们需要依次产生字符‘4’,‘2’,‘6’,和‘7’。
就如在printf函数中使用了%d格式码,它就会执行类似处理。
我们采用的策略是把这个值反复除以10,并打印各个余数。
例如,4267除10的余数是7,但是我们不能直接打印这个余数。
我们需要打印的是机器字符集中表示数字‘7’的值。
在ASCII码中,字符‘7’的值是55,所以我们需要在余数上加上48来获得正确的字符,但是,使用字符常量而不是整型常量可以提高程序的可移植性。
‘0’的ASCII码是48,所以我们用余数加上‘0’,所以有下面的关系:‘0’+ 0 =‘0’‘0’+ 1 =‘1’‘0’+ 2 =‘2’...从这些关系中,我们很容易看出在余数上加上‘0’就可以产生对应字符的代码。
接着就打印出余数。
下一步再取商的值,4267/10等于426。
然后用这个值重复上述步骤。
这种处理方法存在的唯一问题是它产生的数字次序正好相反,它们是逆向打印的。
所以在我们的程序中使用递归来修正这个问题。
我们这个程序中的函数是递归性质的,因为它包含了一个对自身的调用。
乍一看,函数似乎永远不会终止。
当函数调用时,它将调用自身,第2次调用还将调用自身,以此类推,似乎永远调用下去。
这也是我们在刚接触递归时最想不明白的事情。
但是,事实上并不会出现这种情况。
这个程序的递归实现了某种类型的螺旋状while循环。
while循环在循环体每次执行时必须取得某种进展,逐步迫近循环终止条件。
递归函数也是如此,它在每次递归调用后必须越来越接近某种限制条件。
当递归函数符合这个限制条件时,它便不在调用自身。
在程序中,递归函数的限制条件就是变量quotient为零。
在每次递归调用之前,我们都把quotient除以10,所以每递归调用一次,它的值就越来越接近零。
当它最终变成零时,递归便告终止。
/*接受一个整型值(无符号0,把它转换为字符并打印它,前导零被删除*/#include <stdio.h>int binary_to_ascii( unsigned int value){unsigned int quotient;quotient = value / 10;if( quotient != 0)binary_to_ascii( quotient);putchar ( value % 10 + '0' );}递归是如何帮助我们以正确的顺序打印这些字符呢?下面是这个函数的工作流程。
1. 将参数值除以102. 如果quotient的值为非零,调用binary-to-ascii打印quotient当前值的各位数字3. 接着,打印步骤1中除法运算的余数注意在第2个步骤中,我们需要打印的是quotient当前值的各位数字。
我们所面临的问题和最初的问题完全相同,只是变量quotient的值变小了。
我们用刚刚编写的函数(把整数转换为各个数字字符并打印出来)来解决这个问题。
由于quotient 的值越来越小,所以递归最终会终止。
一旦你理解了递归,阅读递归函数最容易的方法不是纠缠于它的执行过程,而是相信递归函数会顺利完成它的任务。
如果你的每个步骤正确无误,你的限制条件设置正确,并且每次调用之后更接近限制条件,递归函数总是能正确的完成任务。
但是,为了理解递归的工作原理,你需要追踪递归调用的执行过程,所以让我们来进行这项工作。
追踪一个递归函数的执行过程的关键是理解函数中所声明的变量是如何存储的。
当函数被调用时,它的变量的空间是创建于运行时堆栈上的。
以前调用的函数的变量扔保留在堆栈上,但他们被新函数的变量所掩盖,因此是不能被访问的。
当递归函数调用自身时,情况于是如此。
每进行一次新的调用,都将创建一批变量,他们将掩盖递归函数前一次调用所创建的变量。
当我追踪一个递归函数的执行过程时,必须把分数不同次调用的变量区分开来,以避免混淆。
程序中的函数有两个变量:参数value和局部变量quotient。
下面的一些图显示了堆栈的状态,当前可以访问的变量位于栈顶。
所有其他调用的变量饰以灰色的阴影,表示他们不能被当前正在执行的函数访问。
假定我们以4267这个值调用递归函数。
当函数刚开始执行时,堆栈的内容如下图所示:执行除法之后,堆栈的内容如下:接着,if语句判断出quotient的值非零,所以对该函数执行递归调用。
当这个函数第二次被调用之初,堆栈的内容如下:堆栈上创建了一批新的变量,隐藏了前面的那批变量,除非当前这次递归调用返回,否则他们是不能被访问的。
再次执行除法运算之后,堆栈的内容如下:quotient的值现在为42,仍然非零,所以需要继续执行递归调用,并再创建一批变量。
在执行完这次调用的出发运算之后,堆栈的内容如下:此时,quotient的值还是非零,仍然需要执行递归调用。
在执行除法运算之后,堆栈的内容如下:不算递归调用语句本身,到目前为止所执行的语句只是除法运算以及对quotient的值进行测试。
由于递归调用这些语句重复执行,所以它的效果类似循环:当quotient的值非零时,把它的值作为初始值重新开始循环。
但是,递归调用将会保存一些信息(这点与循环不同),也就好是保存在堆栈中的变量值。
这些信息很快就会变得非常重要。
现在quotient的值变成了零,递归函数便不再调用自身,而是开始打印输出。
然后函数返回,并开始销毁堆栈上的变量值。
每次调用putchar得到变量value的最后一个数字,方法是对value进行模10取余运算,其结果是一个0到9之间的整数。
把它与字符常量‘0’相加,其结果便是对应于这个数字的ASCII字符,然后把这个字符打印出来。
输出4:接着函数返回,它的变量从堆栈中销毁。
接着,递归函数的前一次调用重新继续执行,她所使用的是自己的变量,他们现在位于堆栈的顶部。
因为它的value值是42,所以调用putchar后打印出来的数字是2。
输出42:接着递归函数的这次调用也返回,它的变量也被销毁,此时位于堆栈顶部的是递归函数再前一次调用的变量。
递归调用从这个位置继续执行,这次打印的数字是6。
在这次调用返回之前,堆栈的内容如下:输出426:现在我们已经展开了整个递归过程,并回到该函数最初的调用。
这次调用打印出数字7,也就是它的value参数除10的余数。
输出4267:然后,这个递归函数就彻底返回到其他函数调用它的地点。
如果你把打印出来的字符一个接一个排在一起,出现在打印机或屏幕上,你将看到正确的值:4267汉诺塔问题递归算法分析:一个庙里有三个柱子,第一个有64个盘子,从上往下盘子越来越大。
要求庙里的老和尚把这64个盘子全部移动到第三个柱子上。
移动的时候始终只能小盘子压着大盘子。
而且每次只能移动一个。
1、此时老和尚(后面我们叫他第一个和尚)觉得很难,所以他想:要是有一个人能把前63个盘子先移动到第二个柱子上,我再把最后一个盘子直接移动到第三个柱子,再让那个人把刚才的前63个盘子从第二个柱子上移动到第三个柱子上,我的任务就完成了,简单。
所以他找了比他年轻的和尚(后面我们叫他第二个和尚),命令:①你丫把前63个盘子移动到第二柱子上②然后我自己把第64个盘子移动到第三个柱子上后③你把前63个盘子移动到第三柱子上2、第二个和尚接了任务,也觉得很难,所以他也和第一个和尚一样想:要是有一个人能把前62个盘子先移动到第三个柱子上,我再把最后一个盘子直接移动到第二个柱子,再让那个人把刚才的前62个盘子从第三个柱子上移动到第三个柱子上,我的任务就完成了,简单。
所以他也找了比他年轻的和尚(后面我们叫他第三和尚),命令:①你把前62个盘子移动到第三柱子上②然后我自己把第63个盘子移动到第二个柱子上后③你把前62个盘子移动到第二柱子上3、第三个和尚接了任务,又把移动前61个盘子的任务依葫芦话瓢的交给了第四个和尚,等等递推下去,直到把任务交给了第64个和尚为止(估计第64个和尚很郁闷,没机会也命令下别人,因为到他这里盘子已经只有一个了)。
4、到此任务下交完成,到各司其职完成的时候了。
完成回推了:第64个和尚移动第1个盘子,把它移开,然后第63个和尚移动他给自己分配的第2个盘子。
第64个和尚再把第1个盘子移动到第2个盘子上。
到这里第64个和尚的任务完成,第63个和尚完成了第62个和尚交给他的任务的第一步。
从上面可以看出,只有第64个和尚的任务完成了,第63个和尚的任务才能完成,只有第2个和尚----第64个和尚的任务完成后,第1个和尚的任务才能完成。
这是一个典型的递归问题。
现在我们以有3个盘子来分析:第1个和尚命令:①第2个和尚你先把第一柱子前2个盘子移动到第二柱子。
(借助第三个柱子)②第1个和尚我自己把第一柱子最后的盘子移动到第三柱子。
③第2个和尚你把前2个盘子从第二柱子移动到第三柱子。
很显然,第二步很容易实现(哎,人总是自私地,把简单留给自己,困难的给别人)。
其中第一步,第2个和尚他有2个盘子,他就命令:①第3个和尚你把第一柱子第1个盘子移动到第三柱子。
(借助第二柱子)②第2个和尚我自己把第一柱子第2个盘子移动到第二柱子上。
③第3个和尚你把第1个盘子从第三柱子移动到第二柱子。
同样,第二步很容易实现,但第3个和尚他只需要移动1个盘子,所以他也不用在下派任务了。
(注意:这就是停止递归的条件,也叫边界值)第三步可以分解为,第2个和尚还是有2个盘子,命令:①第3个和尚你把第二柱子上的第1个盘子移动到第一柱子。
②第2个和尚我把第2个盘子从第二柱子移动到第三柱子。
③第3个和尚你把第一柱子上的盘子移动到第三柱子。
分析组合起来就是:1→3 1→2 3→2 借助第三个柱子移动到第二个柱子|1→3 自私人留给自己的活| 2→1 2→3 1→3借助第一个柱子移动到第三个柱子|共需要七步。
如果是4个盘子,则第一个和尚的命令中第1步和第3步各有3个盘子,所以各需要7步,共14步,再加上第1个和尚的1步,所以4个盘子总共需要移动7+1+7=15步,同样,5个盘子需要15+1+15=31步,6个盘子需要31+1+31=64步……由此可以知道,移动n个盘子需要(2的n次方)-1步。
从上面整体综合分析可知把n个盘子从1座(相当第一柱子)移到3座(相当第三柱子):(1)把1座上(n-1)个盘子借助3座移到2座。