746. 使用最小花费爬楼梯 | 动态规划 | 暴力递归 | 自顶向下

力扣打卡:746. 使用最小花费爬楼梯

解题思路

动态规划的题目还是要写出暴力递归的方法后再去优化

流程

暴力递归最关键的是怎么找到状态转移的方程

  • 状态转移的方程也就是当前的状态和子问题状态之间的联系
  • 怎么得到子问题和当前状态之间的联系呢? 需要用到暴力递归的函数
  • 暴力递归的函数就是求出每一个问题的解,子问题的解
    • 如斐波那契数列,需要两个数的和,那么定义的函数就是求出了前第一个和前第二个函数
    • 不要想着自己定义的函数能否求出来
    • 每次写递归函数: 直接调用函数就就可以得到需要的答案
    • 这样写递归函数的时候才不会出现牛头不对马嘴的情况,比如乱定义参数,乱定义返回值等
  • 在函数中写出当前状态和子问题后就考虑返回的是什么了
自顶向下

写出了暴力递归的方法,多增加 判断 和 记录 就是自顶向下的动态规划了

代码

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        // 在分析暴力递归时,抓住每一个节点,或者是最通用的情况
        // 每个节点的最优体力是什么,肯定是前两个中最小的元素加上本身
        // 题目所给的,我们要分析出当前的对象是谁,我们要先学到的是暴力递归而不是直接写出自底向上的递推


        // 屎一样的题干,我就说怎么示例1不对劲,要爬出去,而不是length-1的位置,是length的位置
        // return Math.min(planA(cost, cost.length-1), planA(cost, cost.length-2)); // 如果想爬出楼顶,那么肯定是前第一个和前第二个中的其中一个
        int[] memo = new int[cost.length+1]; // 比cost多一个就说明了最后一个是楼顶
        Arrays.fill(memo,-1);
        return planB(memo, cost, cost.length); // 最长的
    }

    // 注意分析题目:真不知道这个表达的是什么,还以为写错了
    // 要爬出楼顶,也就是最终的位置是length,而不是length-1
    // 暴力递归的方法就是求出每一个节点的最小值,最终爬出的楼顶的位置一定是length-1或者是length-2
    // 去除最小值即可
    public int planA(int[] cost, int i){
        if(i<0) return Integer.MAX_VALUE; // 表示不可到达
        if(i==0 || i==1) return cost[i]; // 选择从坐标从第0个开始还是从第1个开始

        int spend1 = planA(cost, i-1); // 从0或者1开始前第一个的花费
        int spend2 = planA(cost, i-2); // 从0或者1开始到前第二个的花费
        int spend = Math.min(spend1 , spend2) + cost[i]; // 去除子问题的最小值, 加上本身的花费

        return spend;
    }

    // 写出了暴力递归的方式,自顶向下的动态规划也就是多了判断和记录的两个流程
    // 分析memo,每一个节点都有对应的最小花费,记录这个最小花费即可,此时的长度就是 n 
    public int planB(int[] memo, int[] cost, int i){
        if(i<0) return Integer.MAX_VALUE; // 返回最大值表示不可到达,看题目的要求是什么,如果求最大,那么返回最小值即可
        if(i==0 || i==1) return cost[i];
        if(memo[i] != -1) return memo[i]; // memo中初始化的数据要和题目元素不相干,初始化为-1即可

        int spend1 = planB(memo, cost, i-1); // 从0或者1开始到前第一个的花费
        int spend2 = planB(memo, cost, i-2); // 从0或者1开始到前第二个的花费

        // 因为memo[cost.length] 就是需要返回的结果,但是此时的cost会越界,处理一下即可
        // memo[i] = Math.min(spend1, spend2) + cost[i];
        int spend3 = i==cost.length ? 0 : cost[i]; // 防止索引越界,当然可以在主函数中直接调用 i-1 和 i-2,不归类
        memo[i] = Math.min(spend1, spend2) + spend3;

        return memo[i];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值