暴力递归,暴力递归就是尝试:
- 把问题转换为规模缩小了的同类问题的子问题
- 有明确的不需要继续进行递归的条件(base case)
- 有当得到了子问题的结果之后的决策过程
- 不记录每一个子问题的解
1.汉诺(Hanoi)塔问题
假设有三个命名为 A B C 的塔座,在塔座A上插有n个直径大小不相同,由小到大编号为1,2,3,···,n的圆盘,要求将A座上的圆盘移至塔座C并按同样的顺序叠排。
圆盘移动必须遵守下列规则:
- 每次只能移动一个圆盘 。
- 圆盘可以插在任意一个塔座上 。
- 任何时刻都不能将一个较大的圆盘放在一个较小的圆盘上。
问把所有的圆盘从 A 柱移动到 C 柱总计最少需要多少次移动?
思路:
想要把1..n圆盘从左移动到右分为三步:
- 将1..n-1从左移动到中
- 将n从左移动到右
- 将1..n-1从中移动到右(进入递归,操作略有不同)
最优解步数:O(2n - 1)
1 | // 递归实现,需要左到右、左到中、中到左、中到右、右到左、右到中6种操作 |
进一步观察,简化操作,1..n从from移动到to,第三根柱子为other,可以得到通用的移动步骤:
- 将1..n-1从from移动到other
- 将n从from移动到to
- 将1..n-1从other移动到to(进入递归,操作完全相同)
1 | // 递归简化实现,6种移动动作合一 |
2.打印一个字符串的全部子序列
1 | public static List<String> subs(String s) { |
3.打印一个字符串的全部子序列,要求不要出现重复字面值的子序列
1 | public static List<String> subsNoRepeat(String s) { |
4.打印一个字符串的全部排列
1 | // 第一版递归实现 |
5.打印一个字符串的全部排列,要求不要出现重复的排列
1 | public static List<String> permutation(String s) { |
6.实现栈逆序
逆序给定栈,要求不能申请额外数据结构,只能用递归函数实现。
1 | // 逆序栈 |