多路递归 (Multi Recursion)
斐波那契数列
- 如果每个递归函数例包含多个自身调用,称之为 multi recursion
public static int f(int n) {
if (n == 0) {
return 0;
}
if (n == 1) {
return 1;
}
return f(n - 1) + f(n - 2);
}
- 变体1 - 兔子问题
- 第一个月,有一个未成熟的兔子
- 第二个月,它们成熟
- 第三个月,它们能产下一个新的小兔子
- 所有兔子遵循相同规律,求第 n n n 个月的兔子数
分析
前两个月不能生,从第三个月开始就能生
第n个月的兔子数=第n-1个月的兔子数+第n-1个月成熟的兔子,因为现在它们是2个月到第n个月就能生
而第n-1个月成熟的兔子就等于第n-2个月的全部兔子数,这批兔子到第n个月就恰好第三个月能生,所以
第n个月的兔子数=第n-1个月的兔子数+第n-2月的兔子数
f
(
n
)
f(n)
f(n)=
f
(
n
−
1
)
f(n-1)
f(n−1)+
f
(
n
−
2
)
f(n-2)
f(n−2)其本质还是斐波那契数列,只是从其第一项开始
青蛙爬楼梯
- 楼梯有 n n n 阶
- 青蛙要爬到楼顶,可以一次跳一阶,也可以一次跳两阶
- 只能向上跳,问有多少种跳法
递归优化-记忆法
Memoization 记忆法(也称备忘录)是一种优化技术,通过存储函数调用结果(通常比较昂贵),当再次出现相同的输入(子问题)时,就能实现加速效果,改进后的斐波那契数列代码
public static void main(String[] args) {
int n = 13;
int[] cache = new int[n + 1];
Arrays.fill(cache, -1);
cache[0] = 0;
cache[1] = 1;
System.out.println(f(cache, n));
}
public static int f(int[] cache, int n) {
if (cache[n] != -1) {
return cache[n];
}
cache[n] = f(cache, n - 1) + f(cache, n - 2);
return cache[n];
}
汉诺塔
Tower of Hanoi,是一个源于印度古老传说:大梵天创建世界时做了三根金刚石柱,在一根柱子从下往上按大小顺序摞着 64 片黄金圆盘,大梵天命令婆罗门把圆盘重新摆放在另一根柱子上,并且规定
- 一次只能移动一个圆盘
- 小圆盘上不能放大圆盘
思路
-
假设每根柱子标号 a,b,c,每个圆盘用 1,2,3 … 表示其大小,圆盘初始在 a,要移动到的目标是 c
-
如果只有一个圆盘,此时是最小问题,可以直接求解
- 移动圆盘1
a
↦
c
a \mapsto c
a↦c
- 移动圆盘1
a
↦
c
a \mapsto c
a↦c
-
如果有两个圆盘,那么
- 圆盘1 a ↦ b a \mapsto b a↦b
- 圆盘2 a ↦ c a \mapsto c a↦c
- 圆盘1
b
↦
c
b \mapsto c
b↦c
-
如果有三个圆盘,那么
- 圆盘12 a ↦ b a \mapsto b a↦b
- 圆盘3 a ↦ c a \mapsto c a↦c
- 圆盘12
b
↦
c
b \mapsto c
b↦c
-
如果有四个圆盘,那么
- 圆盘 123 a ↦ b a \mapsto b a↦b
- 圆盘4 a ↦ c a \mapsto c a↦c
- 圆盘 123
b
↦
c
b \mapsto c
b↦c
代码:
public class E02HanoiTower {
/*
源 借 目
h(4, a, b, c) -> h(3, a, c, b)
a -> c
h(3, b, a, c)
*/
static LinkedList<Integer> a = new LinkedList<>();
static LinkedList<Integer> b = new LinkedList<>();
static LinkedList<Integer> c = new LinkedList<>();
static void init(int n) {
for (int i = n; i >= 1; i--) {
a.add(i);
}
}
static void h(int n, LinkedList<Integer> a,
LinkedList<Integer> b,
LinkedList<Integer> c) {
if (n == 0) {
return;
}
h(n - 1, a, c, b);
c.addLast(a.removeLast());
print();
h(n - 1, b, a, c);
}
private static void print() {
System.out.println("-----------------------");
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
public static void main(String[] args) {
init(3);
print();
h(3, a, b, c);
}
}
杨辉三角
- 行 i i i,列 j j j,那么 [ i ] [ j ] [i][j] [i][j] 的取值应为 [ i − 1 ] [ j − 1 ] + [ i − 1 ] [ j ] [i-1][j-1] + [i-1][j] [i−1][j−1]+[i−1][j]
- 当 j = 0 j=0 j=0 或 i = j i=j i=j 时, [ i ] [ j ] [i][j] [i][j] 取值为 1 1 1
public static void print2(int n) {
int[] row = new int[n];
for (int i = 0; i < n; i++) {
// 打印空格
createRow(row, i);
for (int j = 0; j <= i; j++) {
System.out.printf("%-4d", row[j]);
}
System.out.println();
}
}
private static void createRow(int[] row, int i) {
if (i == 0) {
row[0] = 1;
return;
}
for (int j = i; j > 0; j--) {
row[j] = row[j - 1] + row[j];
}
}