张大胖的动态规划——从入门到入土

走楼梯——带权值走楼梯(二)

2018-07-07  本文已影响0人  旺叔叔

LeetCode_746_MinCostClimbingStairs

题目分析:

和上一题非常类似,只是层楼梯带了权值,并且求解不再是步数,而是最小花费。
现在我们开始试着用动态规划的思路来解决问题。

分析出状态转换方程
  dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1]) 
  dp[i]代表“到达”第i层所需最小花费--不包含cost[i]本身的花费
递推初始项
  dp[0] = dp[1] = 0
  根据dp[i]的含义,结合题意可以从任意第1和第2个位置开始,自然都是0

解法一:递归

/**
 * 关键:
 * 1.可以从0 或者 1位置为起始点!
 * 2.梯顶不是最后一个数 而是最后一个数后一个位置!
 * dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1]) (dp[i]代表“到达”第i层所需最小花费)
 * 自底向上(bottom-up)
 */
public static int minCostClimbingStairs_recursion(int n, int[] cost) {
    if(0 == n || 1 == n)
        return 0;

    return Math.min(minCostClimbingStairs_recursion(n-2, cost) + cost[n-2], minCostClimbingStairs_recursion(n-1, cost) + cost[n-1]);
}

解法二:递归-动态规划

/**
 * 关键:
 * 1.可以从0 或者 1位置为起始点!
 * 2.梯顶不是最后一个数 而是最后一个数后一个位置!
 * dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1]) (dp[i]代表“到达”第i层所需最小花费)
 * 自底向上(bottom-up)
 */
public static int minCostClimbingStairs_dp_recursion(int n, int[] cost, int[] dp) {
    if(0 == n || 1 == n)
        return 0;

    if(0 == dp[n])
        dp[n] = Math.min(minCostClimbingStairs_dp_recursion(n-2, cost, dp) + cost[n-2], minCostClimbingStairs_dp_recursion(n-1, cost, dp) + cost[n-1]);
    return dp[n];
}

解法三:循环-动态规划

/**
 * 关键:
 * 1.可以从0 或者 1位置为起始点!
 * 2.梯顶不是最后一个数 而是最后一个数后一个位置!
 * dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1]) (dp[i]代表“到达”第i层所需最小花费)
 * 自底向上(bottom-up)
 * 改为循环
 */
public static int minCostClimbingStairs_dp_loop(int[] cost) {
    int[] dp = new int[cost.length+1];
    for (int i = 2; i < cost.length + 1; ++i) {
        dp[i] = Math.min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1]);
    }
    return dp[cost.length];
}

解法四:循环-动态规划-内存优化

/**
 * 关键:
 * 1.可以从0 或者 1位置为起始点!
 * 2.梯顶不是最后一个数 而是最后一个数后一个位置!
 * dp[i] = cost[i] + min(dp[i- 1], dp[i-2]) (dp[i]代表“经过”第i层所需最小花费)
 * 自底向上(bottom-up)
 * 改为循环
 * 优化内存使用(滚动数组---只使用每一轮计算所需的缓存,通常是上一轮或者多轮的结果)
 * 分析可得 只需要两个int变量交替使用即可达到要求
 */
public static int minCostClimbingStairs_dp_otherWay_loop_lessMemory(int[] cost) {
    int temp1 = cost[0];
    int temp2 = cost[1];
    int res = 0;
    for (int i = 2; i < cost.length; ++i) {
        res = cost[i] + Math.min(temp1, temp2);
        temp1 = temp2;
        temp2 = res;
    }
    return Math.min(temp1, temp2);
}

总结

此题的状态装换方程稍有改变,其他都是一样的,
其实套路就是这么明显,只是不同的人的解答方式不同,有的递归,有的循环,有的优化内存了,有的没优化,
但都是动态规划。
举一反三:题目描述变一下,改成捡金币,就是求最大值了,你能做出来吗?

相应例题的 Github

上一篇下一篇

猜你喜欢

热点阅读