day47打家劫舍1&2&3

力扣198.打家劫舍

题目链接:https://leetcode.cn/problems/house-robber/

思路

1.确定dp数组含义:dp[i]表示偷盗i个房子的最大价值为dp[i]。

2.递推公式:

(1)偷房子i,由于不能偷相邻房子,所以dp[i]=dp[i-2]+nums[i]

(2)不偷房子i,那么就由i-1个房子的状态决定,但是不一定会偷i-1个房子,所以dp[i]=dp[i-1]

(3)取二者最大值,dp[i] = Math.max(dp[i-2] + nums[i],dp[i-1])

3.初始化:

dp[0] = nums[0]

dp[1] = Math.max(nums[0],nums[1])

4.遍历顺序:从前向后

5.打印数组

完整代码

class Solution {
    public int rob(int[] nums) {
        if(nums.length == 1) return nums[0];
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0],nums[1]);
        for (int i = 2; i < nums.length; i++) {
            dp[i] = Math.max(dp[i-2] + nums[i],dp[i-1]);
        }
        return dp[nums.length-1];
    }
}

力扣213.打家劫舍2

题目链接:https://leetcode.cn/problems/house-robber-ii/

思路

例如[2,3,2,3],把环转换成三种情况:

(1)不包含首尾,即[3,2]

(2)包含首,不包含尾,即[2,3,2]

(3)不包含首,包含尾,即[3,2,3]

事实上,情况2和3已经包含了情况1.将情况2和3分别求出,取最大值即可。

自己写的时候还是要注意下标溢出的问题。

完整代码

class Solution {
    public int rob(int[] nums) {
        if(nums.length == 1) return nums[0];
        if(nums.length == 2) return Math.max(nums[0],nums[1]);
        return Math.max(value(nums,0,nums.length-2),
                value(nums,1,nums.length-1));
    }
    public int value(int[] nums,int start,int end){
        int[] dp = new int[nums.length];
        dp[start] = nums[start];
        dp[start+1] = Math.max(nums[start],nums[start+1]);
        for (int i = 2; i <= end; i++) {
            dp[i] = Math.max(dp[i-2] + nums[i],dp[i-1]);
        }
        return dp[end];
    }
}

力扣337.打家劫舍3

题目链接:https://leetcode.cn/problems/house-robber-iii/

思路

用一个长度为2的一维数组dp[]来表示当前节点是偷还是不偷:**dp[0]表示不偷当前节点所拥有的最大价值;dp[1]表示偷当前节点所拥有的最大价值。**那么,

(1)不偷当前节点,最大价值=左孩子偷还是不偷的最大价值+右孩子偷还是不偷的最大价值

(2)偷当前节点,那么它的左右孩子肯定不能偷了,最大价值=当前节点价值+左孩子不偷的最大价值+右孩子不偷的最大价值

1.确定递归参数和返回值:参数是传进去的节点。返回值是一个长度为2的一维数组,表示偷或不偷当前节点所拥有的最大价值

2.终止条件:当遍历到空结点,无论偷不偷,价值都是0

3.单层循环:
**
必须采用后序遍历,因为计算当前节点偷不偷的价值依靠左右孩子的返回值**

中节点的处理逻辑:

dp[1] = root.val + leftdp[0] +rightdp[0];
dp[0] = Math.max(leftdp[0],leftdp[1]) +
        Math.max(rightdp[0],rightdp[1]);

左右孩子定义一个一维数组来接住返回值:

int[] leftdp = traversal(root.left);
int[] rightdp = traversal(root.right);

完整代码

class Solution {
    public int rob(TreeNode root) {
        int[] dp = traversal(root);
        return Math.max(dp[0],dp[1]);
    }
    //dp[0]表示不偷,dp[1]表示偷
    public int[] traversal(TreeNode root){
        int[] dp = new int[2];
        if(root == null) return dp;

        int[] leftdp = traversal(root.left);
        int[] rightdp = traversal(root.right);

        dp[1] = root.val + leftdp[0] +rightdp[0];
        dp[0] = Math.max(leftdp[0],leftdp[1]) +
                Math.max(rightdp[0],rightdp[1]);
        return dp;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值