To Iterate is Human, to Recurse, Divine.—— L. Peter Deutsch
很多时候迭代是一种“扫描”全部情况以获得解的过程;而递归往往是把问题划分为操作过程相同的子问题来求解。递归函数是自身调用自身的函数。
请完成一个经典的递归入门实例:求n的阶乘。不要想着循环,而要从把问题分解为相同的子问题的角度考虑这个问题:
n!=n*(n-1)!
即,n的阶乘等于n乘n-1的阶乘,(n-1)的阶乘等于n-1乘(n-1)-1的阶乘……直到n为1时。
所以,我们可以构建一个函数来求n!:
1、在这个函数里只需要接收一个参数n,它表示要求n的阶乘;
2、在函数中计算当前数n的阶乘时,用n*(n-1)!的阶乘,而计算(n-1)!时只需要调用当前函数,并且参数为n-1即可;
3、在计算过程需要用到函数运行的结果,所以这个函数应该有一个返回值(int、long long之类的);
4、特殊的:当n为1的时候,我们不能继续调用这个函数了——直接返回1,因为1!=1。
下图详细描述了求5!的过程:
一行,一个正整数n。
对于100%的数据:
1\le n \le 11 。
120
5
120
设计一个递归函数需要遵循以下原则:
前提: 子问题处理过程相同,最终无需递归。
设计方法: 1、解决子问题需要哪些数据——函数参数;
2、结果用什么形式返回——函数返回值;
3、何时调用自己,何时达到边界——函数内的处理逻辑。
关于使用函数参数、函数返回值、全局变量来传递数据的差异,在学习回溯的过程中我们将会深入理解。
对于当前的问题,我们可以设计这样的函数(处理过程):
//函数的作用是计算n!
//参数n表示当前要计算的值
//计算过程n!=n*(n-1)!需要(n-1)!的结果,所以有返回值
long long jc(int n){
if(n==1){
//递归边界:当n==1时,无需调用自己,直接返回1!的值。
return ?;
}else{
//递归过程:当n>1时,n!=n*(n-1)!。
return ?;
}
}