主题:递归
递归是一种编程技巧,比如在 DFS 和 前中后序二叉树遍历中,都使用了递归的思想。
使用递归需要满足的是三个条件:
- 一个问题的解可以分解为几个问题的解
- 这个问题和分解之后的子问题,处理数据规模的不同,求解的思路是相同的
- 存在递归的终止条件
如何写出递归代码:
数学归纳法,找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,找出递归的终止条件。
注意
- 递归代码要警惕堆栈溢出,即 StackOverflowError,解决方法可以设置最大的递归深度
- 递归代码要避免重复计算,可以借助散列表避免重复计算
示例:
n 个台阶,每次只能跨 1 个或者 2 个台阶,问共有几种跨法?
- 总结规律
f(0) = 0;
f(1) = 1;
f(2) = 2; // 1,1 2
f(3) = 3; // 1,2 2,1 1,1,1
f(4) = 5; // 1,1,1,1 1,1,2 1,2,1 2,2
…
f(n) = f(n-1) + f(n-2) - 找到终止条件
终止条件是 n=1 和 n = 2 的时候
funciton (int n) {
if (n == 1) return 1;
if (n == 2) return 2;
return f (n-1) + f (n-2);
}
但是这种计算方式正如上边所说的,会重复计算。比如 f(5) = f(4) + f(3)
, f(4) = f(3) + f(2),这里 f(3) 计算了两次。所以可以借用哈希表来避免重复计算。
function (int n) {
if(n == 1) return 1;
if(n == 2) return 2;
if(map.containsKey(n)) return map.get(n);
int ret = f(n-1) + f(n-2);
map.put(n, ret);
return ret;
}