内涵
定义
在数学与计算机科学中,**递归(Recursion)是指在函数的定义中使用函数自身的方法。**实际上,递归,顾名思义,其包含了两个意思:递 和 归,这正是递归思想的精华所在
递归思想的内涵
递归就是有去(递去)有回(归来)
- **“有去”**是指:递归问题必须可以分解为若干个规模较小,与原问题形式相同的子问题,这些子问题可以用相同的解题思路来解决,就像上面例子中的钥匙可以打开后面所有门上的锁一样
- **“有回”**是指 : 这些问题的演化过程是一个从大到小,由近及远的过程,并且会有一个明确的终点(临界点),一旦到达了这个临界点,就不用再往更小、更远的地方走下去
递归的基本思想就是把规模大的问题转化为规模小的相似的子问题来解决
递归的三要素
- 明确递归终止条件;
- 给出递归终止时的处理办法;
- 提取重复的逻辑,缩小问题规模。
递归的应用场景
- 问题的定义是按递归定义的(Fibonacci函数,阶乘,…);
- 问题的解法是递归的(有些问题只能使用递归方法来解决,例如,汉诺塔问题,…);
- 数据结构是递归的(链表、树等的操作,包括树的遍历,树的深度,…)。
经典递归问题实战
阶乘
public class Factorial { public static long f( int n ) { if ( n == 1 ) /* 递归终止条件 */ return(1); /* 简单情景 */ return(n * f( n - 1 ) ); /* 相同重复逻辑,缩小问题的规模 */ } public static long f_loop( int n ) { long result = n; while ( n > 1 ) { n--; result = result * n; } return(result); }}复制代码
斐波纳契数列
public class FibonacciSequence { public static int fibonacci( int n ) { if ( n == 1 || n == 2 ) /* 递归终止条件 */ { return(1); /* 简单情景 */ } return(fibonacci( n - 1 ) + fibonacci( n - 2 ) ); /* 相同重复逻辑,缩小问题的规模 */ } public static int optimizeFibonacci( int first, int second, int n ) { if ( n > 0 ) { if ( n == 1 ) /* 递归终止条件 */ { return(first); /* 简单情景 */ }else if ( n == 2 ) /* 递归终止条件 */ { return(second); /* 简单情景 */ }else if ( n == 3 ) /* 递归终止条件 */ { return(first + second); /* 简单情景 */ } return(optimizeFibonacci( second, first + second, n - 1 ) ); /* 相同重复逻辑,缩小问题规模 */ } return(-1); } public static int fibonacci_loop( int n ) { if ( n == 1 || n == 2 ) { return(1); } int result = -1; int first = 1; /* 自己维护的"栈",以便状态回溯 */ int second = 1; /* 自己维护的"栈",以便状态回溯 */ for ( int i = 3; i <= n; i++ ) /* 循环 */ { result = first + second; first = second; second = result; } return(result); } public static int fibonacci_array( int n ) { if ( n > 0 ) { int[] arr = new int[n]; /* 使用临时数组存储斐波纳契数列 */ arr[0] = arr[1] = 1; for ( int i = 2; i < n; i++ ) /* 为临时数组赋值 */ { arr[i] = arr[i - 1] + arr[i - 2]; } return(arr[n - 1]); } return(-1); }}复制代码
杨辉三角的取值
public static int getValue( int x, int y ){ if ( y <= x && y >= 0 ) { if ( y == 0 || x == y ) /* 递归终止条件 */ { return(1); }else{ /* 递归调用,缩小问题的规模 */ return(getValue( x - 1, y - 1 ) + getValue( x - 1, y ) ); } } return(-1);}}复制代码
回文字符串的判断
/** * Title: 回文字符串的判断 * Description: 回文字符串就是正读倒读都一样的字符串。如"98789", "abccba"都是回文字符 * 两种解法: * 递归判断; * 循环判断; */public class PalindromeString { /** * @description 递归判断一个字符串是否是回文字符串 * @return */ public static boolean isPalindromeString_recursive( String s ) { int start = 0; int end = s.length() - 1; if ( end > start ) {//递归终止条件:两个指针相向移动,当start超过end时,完成判断 if ( s.charAt( start ) != s.charAt( end ) ){ return(false); }else{ /* 递归调用,缩小问题的规模 */ return(isPalindromeString_recursive( s.substring( start + 1 ).substring( 0, end - 1 ) ) ); } } return(true); } /** * @description 循环判断回文字符串 * @return */ public static boolean isPalindromeString_loop( String s ) { char[] str = s.toCharArray(); int start = 0; int end = str.length - 1; while ( end > start ) //循环终止条件:两个指针相向移动,当start超过end时,完成判断 { if ( str[end] != str[start] ) { return(false); }else{ end--; start++; } } return(true); }}复制代码