关于动态规划
动态规划算法的核心就是记住已经解决过的子问题的解。
动态规划有几个典型特征:最优子结构、状态转移方程、边界、重叠子问题。
什么样的问题可以考虑使用动态规划解决呢?
- 如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。
动态规划问题的解题思路:
- 穷举分析
- 确定边界
- 找出规律,确定最优子结构
- 写出状态转移方程
动态规划的求解方式有两种:
- 自顶向下的备忘录法
- 自底向上
用这两个方法来解决一个经典的问题:斐波那契数列
方法一: 自顶向下的备忘录法
public static int fib(int n){
if(n<=0){
return n;
}
int[] nums=new int[n+1];
for(int i=0;i<=n;i++){
nums[i]=-1;
}
return fib(n, nums);
}
public static int fib(int n,int []nums)
{
if(nums[n]!=-1) {//如果不是-1,则表明n的值已经被算过不需要重新计算
return nums[n];
}
if(n<=2) {
nums[n] = 1;
}
else {
nums[n]=fib( n-1,nums)+fib(n-2,nums);
}
return nums[n];
}
方法二: 自底向上
public static int fib(int n){
if(n == 1){
return 1;
}
if(n == 2){
return 2;
}
int[] nums = new int[n + 1];//创建一个用来保存fib第n次的结果的数组
nums[1] = 1;
nums[2] = 2;
for(int i = 3; i <= n; i++){
nums[i] = nums[i - 1] + nums[i - 2];
}
return nums[n];
}
根据DP的解题思路,来写一下斐波那契数列问题的过程:
- 穷举分析
- 当n = 1时,f(1) = 1;
- 当n = 2时,f(2) = 2;
- 当n = 3时,f(3) = 3;
- 当n = 4时,f(4) = 5;
- 当n = 5时,f(5) = 8;
- 当n = 6时,f(6) = 13;
- 当n = 7时,f(7) = 21;
- …
-
确定边界:
根据穷举我们发现,当n大于3已经呈现出规律f(3) = f(2) + f(1) =3,因此f(1) =1,f(2) = 2就是fib的边界。 -
找出规律,确定最优子结构
明显是:f(n) = f(n-1) + f(n-2) -
写出状态转移方程
根据前面三步就可以得到状态转移方程了:if(n == 1) f(1) = 1; if(n == 2) f(2) = 2; else f(n) = f(n - 1) + f(n - 2);
例题:
持续更新。。。