算法这一块,动态规划问题的一般形式就是求最值,在计算机问题上应用比较多,需要多探究,这是我对动态规划的一个练习入门-斐波拉契数列
/**
* 斐波拉契 练习动态规划
* { 1 , n=1 | n=2
* f(x) = {
* { f(x-2) + f(x-1)
* @author
*/
public class Fibonacci {
/**
* 暴力递归 直接根据方程进行递归,
* 但是这种方法 会重复计算多次
* 如 f(5)
* f(4) f(3)
* / \
* f(3) + f(2) f(2) f(1)
* / \
* f(2)+f(1)
* 其中就会发现 右部f(3)分支就是重复计算的 ,如果值大时 直接爆炸
* @param x
* @return
*/
public static int violentRecursion(int x){
if(x <= 2){
return 1;
}
return violentRecursion(x - 2)+violentRecursion(x-1);
}
/**
* 减少重复计算的递归
* 首先定义一个可以保存计算值的存储空间 如下使用的便是数组 ,也可以用hash表
* 每次计算时 将 x 计算出的 f(x)进行存储,下次计算时便可直接取出,不再重复计算
*
* @param x
* @return
*/
public static int singleRecursion(int x){
// 定义f(x) 存储空间
int[] fx = new int[x+1];
int l = singleRecursion(x, fx);
return l;
}
public static int singleRecursion(int x,int[] fx){
if(x <= 2){
return 1;
}
// 存在f(x)值,直接取出
if(fx[(int) x] != 0){
return fx[(int) x];
}
// 不存在则通过递归计算保存
fx[x] = singleRecursion(x-2,fx) + singleRecursion(x-1,fx);
return fx[x];
}
/**
* 动态规划 Dynamic programming (这是重点!!)
* 使用 动态表的方式进行计算
* 定义出计算值大小的空间存储表,为了直观表达 (f(x) = dp[x]) 长度申请为x+1
* 依次计算 1~x 值
* @param x
* @return
*/
public static int dpTable(int x){
int[] dp = new int[x+1];
dp[1] = dp[2] = 1;
for (int j = 3; j < dp.length; j++) {
dp[j] = dp[j-2]+dp[j-1];
}
return dp[x];
}
/**
* 动态规划 Dynamic programming 优化
* 前面使用动态表的方式就会发现,在此题中我们不需要保存 1~x-1的值,
* 所以可以对空间进行省略,不使用额外空间进行存储值 ,只需要使用两个变量来保存 x-1 与 x-2 的值便可以计算出 f(x)
* 使用 pre保存上次计算值,cur保存当前计算值, 计算出下次的值 calcCur= pre + cur 并替换 pre cur
* @param x
* @return
*/
public static int dp(int x){
//定义初始 f(1) = 1 f(2) = 1;
int pre = 1,cur = 1;
//计算出 f(3~x) 并更改变量保存值
for (int i = 3; i <= x; i++) {
int calcCur = pre + cur;
pre = cur;
cur = calcCur;
}
return cur;
}
}