递归问题的解题思路
递归的设计经验
- 找重复(子问题)
- 找到一种划分方法
- 找到递推公式或者等价转换
都是父问题转换为求解子问题
- 找重复中的变化量
- 变化的量通常要作为参数
- 找参数变化趋势——>设计出口
- 根据参数变化的趋势,对边界进行控制,适时终止递归
递归的基础练习
1. 切蛋糕思维例题:
1. 求阶乘
/**
* f1(n):求n的阶乘-->f1(n-1)求n-1的阶乘
* 找重复:n*(n-1)的阶乘,求n-1的阶乘是原问题的重复(规模更小)——子问题
* 找变化:变化的量应该作为参数
* 找边界:出口*/
public class Demo05
{
public static void main(String[] args)
{
int a=3;
int result=f1(a);
System.out.println(result);
}
public static int f1(int n)
{
if (n==1) return 1;
return n*f1(n-1);
}
}
2. 打印从i到j
/**
* 打印i到j
* 找重复:
* 找变化:变化的量应该作为参数
* 找边界:出口*/
public static void f2(int i,int j) {
if (i>j) return;
System.out.print(i+" ");
f2(i+1,j);
}
3. 对arr数组的所有元素求和
public static int f3(int[] arr,int begin)
{
if (begin==arr.length-1)
return arr[begin];
return (arr[begin]+f3(arr, begin+1));
}
4.翻转字符串
public static String f4(String src,int end) {
if (end==0)
{
return ""+src.charAt(0);//只有一个元素
}
return src.charAt(end)+f4(src, end-1);
}
2.找递推公式或等价转换例题
5.斐波那契数列
//递推公式
public static int f5(int i) {
if (i==1||i==2)
return 1;
return f5(i-1)+f5(i-2);
}
6.最大公约数 f(m,n)=f(n,m%n)
//等价转换 f(m,n)=f(n,m%n)辗转相除
public static int f6(int m,int n) {
if (n==0) return m;
return f6(n,m%n);
}
7.排序改递归
import java.util.Arrays;
public class Main {
public static void main(String[] args){
int arr[]= {9,6,5,8,4,7,1,3,2};
insertSort(arr,8);
System.out.print(Arrays.toString(arr));//1,2,3,4,5,6,7,8,9
}
public static void insertSort(int []arr,int k) {
//递归出口
if(k==0)
return;
//对前k-1个元素排序
insertSort(arr,k-1);
//把位置k的元素插入到前面的部分
int x=arr[k];
int index=k-1;
while(index>-1&&x<arr[index]) {//小的往前插
arr[index+1]=arr[index];
index--;
}
arr[index+1]=x;
}
}
8.汉诺塔
算法分析(递归算法)
实现这个算法可以简单分为三个步骤:
(1) 把n-1个盘子由A 移到 B;
(2) 把第n个盘子由 A移到 C;
(3) 把n-1个盘子由B 移到 C;
从这里入手,在加上上面数学问题解法的分析,我们不难发现,移到的步数必定为奇数步:
(1)中间的一步是把最大的一个盘子由A移到C上去;
(2)中间一步之上可以看成把A上n-1个盘子通过借助辅助塔(C塔)移到了B上,
(3)中间一步之下可以看成把B上n-1个盘子通过借助辅助塔(A塔)移到了C上;
代码实现
public class Hanoi
{
public static void main(String[] args)
{
String from="A";
String to="B";
String help="C";
printHanoiTower(3, from, to, help);
}
/**
*
* @param N 初始的N个从小到大的盘子,N是最大编号
* @param from 原始柱子
* @param to 目标柱子
* @param help 辅助的柱子
*/
/**
1-N从A移动到B,C作为辅助
等价于:
1、1~N-1从A移动到C,B为辅助
2、把N从A移动到B
3、1-N-1从C移动到B,A为辅助
*/
static void printHanoiTower(int N,String from,String to,String help) {
if (N==1)
{
System.out.println("move"+N+" from"+from+" to"+to);
return;
}
printHanoiTower(N-1, from, help, to);//先把N-1个盘子移动到辅助空间上去
System.out.println("move"+N+" from"+from+" to"+to);//N可以顺利的到达target
printHanoiTower(N-1, help, to, from);//让N-1从辅助空间回到源空间上去
}
}
运行结果
move1 fromA toB
move2 fromA toC
move1 fromB toC
move3 fromA toB
move1 fromC toA
move2 fromC toB
move1 fromA toB