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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 在介绍动态规划的核心思想前,先看一道题。 LeetCode_70_ClimbingStairs 题目分析: 解法一...
    旺叔叔阅读 1,612评论 2 13
  • 有人说:守望着一座城市,是希望能在这座城市的某个时候,某个角落里遇见另一个人… 1个宇宙,9大行星,204个国家,...
    浅默疏影阅读 261评论 0 0
  • Chapter 4 彭罗斯楼梯 1 安燃点了一根烟,但是她不会抽。她把烟夹在指间,努力回忆着之前看到过的抽烟的女人...
    君七寻阅读 543评论 0 2

友情链接更多精彩内容