递归:将问题分解成子问题求解,从较小的问题逐渐逼近原始问题,很多时候只需要在f(n-1)中加入或移除某些东西或稍作修改就可以求得f(n)
动态规划与递归的区别:动态规划要将中间的结果缓存起来以备后续使用
1、斐波那契数列问题
public class fibonacci {
private final static int max=1000;
/**
* 递归方法,时间复杂度2^i
* @param i
* @return
*/
public static long recursion(int i) {
if (i == 0)
return 0;
if (i == 1)
return 1;
return recursion(i - 1) + recursion(i - 2);
}
private static long[] temp=new long[max];
/**
* 动态规划方法,将中间结果缓存起来,时间复杂度 i
* @param i
* @return
*/
public static long dynamic(int i){
if (i == 0)
return 0;
if (i == 1)
return 1;
if(temp[i]!=0){
return temp[i];
}
temp[i]=dynamic(i-1)+dynamic(i-2);
return temp[i];
}
public static void main(String[]args) {
long startTime = System.currentTimeMillis(); // 获取开始时间
System.out.println(recursion(40));
long endTime = System.currentTimeMillis(); // 获取结束时间
System.out.println("程序运行时间: " + (endTime - startTime) + "ms");
long startTime2 = System.currentTimeMillis(); // 获取开始时间
System.out.println(dynamic(40));
long endTime2 = System.currentTimeMillis(); // 获取结束时间
System.out.println("程序运行时间: " + (endTime2 - startTime2) + "ms");
}
}
运行结果
102334155
程序运行时间: 1145ms
102334155
程序运行时间: 0ms
递归算法的空间效率很低,每次递归调用都会在栈上增加一层
扩展:
用8个1*2的小长条去覆盖一个2*8的棋盘,要求完全覆盖棋盘,小长条彼此不重叠。求总共有多少总覆盖方法。
其实就是fibonacci数列
2、楼梯问题
楼梯有n阶台阶,一次可以上1阶,2阶,或3阶,计算有多少种上楼梯的方式
小孩上完楼梯最后一步即抵达第n阶的那一步,可能走1阶或2阶或3阶,最后一步可能是第n-1阶向上走1,或n-2向上走2,或n-3向上走3,同样用递归问题可以解决
public class stair {
public static int getMethods(int num) {
if (num<0) {
return 0;
}
if (num==0) {
return 1;
}
return getMethods(num-1)+getMethods(num-2)+getMethods(num-3);
}
public static void main(String[] args) {
System.out.println(getMethods(6));
}
}
输出结果为:
24
扩展:
用1分、2分和5分的硬币凑成1元,共有多少种不同的凑法?(华为机试题)
这个不能用上述方法,因为走楼梯不同顺序是不同的走法,而硬币的凑法则与顺序无关,写程序可用穷举法
public class coin {
public static int getKinds(){
int num=0;
for (int i = 0; i
for (int j = 0; j <= 100-5*i; j++) {
for (int k = 0; k <= 100-5*i-2*j; k++) {
if(5*i+2*j+k==100){
num++;
}
}
}
}
return num;
}
public static void main(String[] args) {
System.out.println(getKinds());
}
}
输出:
541
3、编写一个方法返回集合的所有子集
4、编写一个方法确定字符串的所有排列组合