夸父追日:第九章 动态规划part07

今日收获:打家劫舍,打家劫舍Ⅱ,打家劫舍Ⅲ

1. 打家劫舍

题目链接:198. 打家劫舍 - 力扣(LeetCode)

思路:

(1)dp数组:表示下标 i 及之前能偷盗的最大金额。

(2)初始化:数组的前两个下标能偷盗的最大值。

(3)递推公式:当前位置是否偷要根据前两个位置取最大值推出来。dp[i-2]+nums[i] 表示偷盗当前位置;dp[i-1] 表示不偷盗当前位置。

注意要判断数组下标是否越界。

方法:

class Solution {
    public int rob(int[] nums) {
        int len=nums.length;

        if (len==1){
            return nums[0];
        }

        // 下标i及之前偷盗的最大值
        int[] dp=new int[len];
        // 初始化
        dp[0]=nums[0];
        dp[1]=nums[0]>nums[1]?nums[0]:nums[1];

        // 当前结果取决于前两个结果,从左到右遍历
        for (int i=2;i<len;i++){
            dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1]);  // 偷与不偷是个问题
        }

        return dp[len-1];
    }
}

2. 打家劫舍Ⅱ

题目链接:213. 打家劫舍 II - 力扣(LeetCode)

思路:将环形问题转换为线性数组问题,就可以转化为线性的打家劫舍问题。因为头尾不能同时选择,所以可以分成两种情况:不考虑尾实体 & 不考虑头实体,再求两者中用线性打家劫舍求得结果的最大值。

方法:

class Solution {
    public int rob(int[] nums) {
        int len=nums.length;

        if (len==1){
            return nums[0];
        }

        if (len==2){
            return Math.max(nums[0],nums[1]);
        }

        int dpHead=array(nums,0,len-1);  // 不考虑尾元素
        int dpTail=array(nums,1,len);  // 不考虑头元素

        return dpHead>dpTail?dpHead:dpTail;
    }

    public int array(int[] nums,int start,int end){  // 左闭右开区间
        int len=end-start;

        // 下标i及之前偷盗的最大值
        int[] dp=new int[len];
        // 初始化
        dp[0]=nums[start];
        dp[1]=nums[start]>nums[start+1]?nums[start]:nums[start+1];

        // 当前结果取决于前两个结果,从左到右遍历
        for (int i=2;i<len;i++){
            dp[i]=Math.max(dp[i-2]+nums[start+i],dp[i-1]);  // 偷与不偷是个问题
        }

        return dp[len-1];
    }
}

3. 打家劫舍Ⅲ

题目链接:337. 打家劫舍 III - 力扣(LeetCode)

思路:后序递归遍历。

(1)dp数组定义:长度为2,两个元素分别表示偷当前节点和不偷当前节点的最大值。

(2)递推公式:如果偷当前节点,则数组的值为当前节点的值加上不偷左右孩子的值;如果不偷当前节点,则分别比较左右孩子的dp数组元素最大值再相加。

方法:

class Solution {
    public int rob(TreeNode root) {
        // 二叉树递归遍历
        int[] dp=robTree(root);  // dp数组的长度为2,分别表示偷和不偷当前节点
        return Math.max(dp[0],dp[1]);  
    }

    public int[] robTree(TreeNode node){
        if (node==null){
            return new int[]{0,0};
        }

        int[] left=robTree(node.left);
        int[] right=robTree(node.right);

        int[] dp=new int[2];
        // 偷当前节点,不偷左右孩子
        dp[1]=node.val+left[0]+right[0];
        // 不偷当前节点
        dp[0]=Math.max(left[0],left[1])+Math.max(right[0],right[1]);

        return dp;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值