198. 打家劫舍 | 动态规划 | 暴力递归 | 自顶向下分析

力扣打卡:198. 打家劫舍

解题思路

理解题目
给定一组数组,找到数组中,一组和最大的序列

对于数组中的每一个元素

  • 对于其和其后的元素,都有一个最大的序列

注意题目中的寻找所有可能的过程中:就是回溯的过程,这个也就是动态规划和回溯的重要区别,动态规划能够消除重复的子问题

具体来看看 planA() 纯暴力递归
public int planA(int p, int[] nums){
    if(p>nums.length-1) return Integer.MIN_VALUE; // 将整数的最小值返回,超出索引,表示偷窃的不可达

    // 当前的已经偷窃了,那么此时应该是下一个的下一个,而不是下一个
    int max = 0;
    for(int i=p; i<nums.length; i++){
        int sub = planA(i+2, nums); // 此时还可以变为next的next的next,依次类推
        max = Math.max(max, sub);
    }
    return max + nums[p]; // 表示加上当前的金额
}

写暴力递归或者是写动态规划,最重要的还是找到状态转移的过程,也就是当前状态和子问题状态之间的联系

具体来说就是:怎么将子问题的结果应用到当前的状态上,也就是题目给出的一些动作或者行为
  • 每次只能往下往右走(问题:寻找多少种路径到达finish节点 或者 怎么走能够得到最大的 value
  • 每次只能走一个台阶或者两个台阶(问题:多少种方式可以走到楼顶 或者 最小的步数走到楼顶 或者 花费最小的体力走到楼顶)
  • 当前的数等于前一个和第前二个数的和(问题:给定一个n,求出第n个数的值,斐波那契数列)
  • 当前的数至少分解成两个数(问题:求给定一个数的最大乘积)

重点

  • 写递归函数,这个函数得到的结果一般要与题目要求的一致
  • 写递归函数,就一定要认为这个递归可以得到子问题的结果,不要考虑是否可以得到呢,该怎么写呢,其实递归按照函数的定义来就可以了

代码

class Solution {
    public int rob(int[] nums) {
        // return planA(0, nums);
        int[]memo = new int[nums.length];
        Arrays.fill(memo, -1);
        int max = 0;
        for(int i=0; i<nums.length; i++){
            max = Math.max(max, planB(i, nums, memo));
        }
        return max;
    }
    // 可以用回溯来做
    // 同时可以清楚的看到这个可以使用动态规划来做,因为每一个节点,都有一个最高的金额

    // 分析:按照给定的数组,假设 偷窃的顺序为 从头到尾, 那么对于每一个节点都会有最高的金额

    public int planA(int p, int[] nums){
        if(p>nums.length-1) return Integer.MIN_VALUE; // 将整数的最小值返回,超出索引,表示偷窃的不可达

        // 当前的已经偷窃了,那么此时应该是下一个的下一个,而不是下一个
        int max = 0;
        for(int i=p; i<nums.length; i++){
            int sub = planA(i+2, nums); // 此时还可以变为next的next的next,依次类推
            max = Math.max(max, sub);
        }
        return max + nums[p]; // 表示加上当前的金额
    }

    public int planB(int p, int[] nums, int[] memo){
        if(p>nums.length-1) return Integer.MIN_VALUE;
        if(memo[p] != -1) return memo[p];

        int max = 0;
        for(int i=p; i<nums.length; i++){
            int sub = planB(i+2, nums, memo);
            max = Math.max(max, sub);
        }
        memo[p] = max + nums[p];
        return memo[p];
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值