动态规划
基础知识
动态规划问题,我将拆解为如下五步曲:
labuladuo的解析:
出现问题,先思考这三个问题:
这道题目我举例推导状态转移公式了么?
我打印dp数组的日志了么?
打印出来了dp数组和我想的一样么?
Leecode题目
509. 斐波那契数
最简单的递归:(时间复杂度= 递归调用次数 x 单次函数的时间 )
class Solution {
public int fib(int n) {
if(n==0||n==1) return n;
return fib(n-1)+fib(n-2);
}
}
Memoization 记忆法(也称备忘录)是一种优化技术,通过存储函数调用结果(通常比较昂贵),当再次出现相同的输入(子问题)时,就能实现加速效果,改进后的代码(用一维数组存储之前计算过的元素)
记忆法是动态规划的一种情况,强调的是自顶向下的解决(递归)
class Solution {
public int fib(int n) {
if(n==0||n==1){
return n;
}
int[ ] cache =new int[n+1];
Arrays.fill(cache,-1);
cache[0] =0;
cache[1] = 1;
return helper(n,cache);
}
private int helper(int n, int[] cache){
//先判断cache[n] 是否被计算
if(cache[n] !=-1){
return cache[n];
}
// 没有的话,计算一边
int x = helper(n-1,cache);
int y = helper(n-2,cache);
cache[n] =x+y;
return cache[n];
}
}
我们想要的是自底向上的dp(for循环):
dp[ ] 数组里面装的东西和cache[ ]数组装的是一样的。
class Solution {
public int fib(int n) {
if(n<=1){
return n;
}
int[] dp = new int[n+1];
dp[0] =0;
dp[1] =1;
for(int i=2;i<=n;i++){
dp[i] = dp[i-1]+dp[i-2];
}
return dp[n];
}
}
70.爬楼梯
递归—记忆法优化—自顶向下的递归
class Solution {
public int climbStairs( int n) {
int[] cache = new int[n+1];
Arrays.fill(cache,-1);
cache[0] = 1;
cache[1]=1;
int result = recursive(cache,n);
return result;
}
public int recursive( int[] cache,int n){
if(cache[n]!=-1){
return cache[n];
}
cache[n]= recursive(cache,n-1)+ recursive(cache,n-2);
return cache[n];
}
}
方法二:dp–自底向上的for循环:
class Solution {
public int climbStairs( int n) {
if(n<2) return 1;
int[] dp = new int[n+1];
dp[0] =1;
dp[1] =1;
for( int i=2;i<=n;i++){
dp[i] = dp[i-1]+dp[i-2];
}
return dp[n];
}
}
746. 使用最小花费爬楼梯
class Solution {
public int minCostClimbingStairs(int[] cost) {
if(cost.length<2) return cost[0];
int len = cost.length;
int[] dp = new int[len+1];
dp[0] =0;
dp[1]=0; //因为题目说可以从下标0和1的台阶开始爬楼梯
for(int i=2;i<=len;i++){
dp[i] = Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
}
return dp[len];
}
}