day39 打家劫舍

### 9.22 198. House Robber
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
https://leetcode.cn/problems/house-robber/description/
198.打家劫舍  
https://www.bilibili.com/video/BV1Te411N7SX
https://programmercarl.com/0198.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D.html  

dp`[j] : 路过第j家时抢到的最大钱数
dp`[0] = 0;

```java
public class houseRobber {  
    public int rob(int[] nums) {  
        int[] dp = new int[nums.length];  
        //如果只有一家,那么一定抢  
        if(nums.length == 1) return nums[0];  
  
        //初始化  
        dp[0] = nums[0];  
        dp[1] = Math.max(nums[0],nums[1]);  
  
        //本题不是背包问题,没有背包容量,无需考虑是先遍历背包还是先遍历物品  
        for (int i = 2; i < dp.length; i++) {  
                dp[i] = Math.max((dp[i-2] + nums[i]),dp[i-1]);  
        }  
  
        return dp[nums.length - 1];  
    }  
}  
class houseRobberTest {  
    public static void main(String[] args) {  
        houseRobber example = new houseRobber();  
        int[] nums = {3};  
        System.out.println(example.rob(nums));  
    }  
}
```
### 9.23 213. House Robber II
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
https://leetcode.cn/problems/house-robber-ii/description/
213.打家劫舍II  
https://www.bilibili.com/video/BV1oM411B7xq
https://programmercarl.com/0213.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DII.html 

自己写的答案:
```java
public class houseRobber2 {  
    public int rob(int[] nums) {  
        int length = nums.length;  
        if(length == 1) return nums[0];  
        if(length == 2) return Math.max(nums[0],nums[1]);  
  
        int[] dp = new int[nums.length];  
        dp[0] = Math.max(Math.max(nums[0],nums[1]),nums[length-1]);  
        dp[1] = Math.max(nums[0],nums[1]);  
  
        for (int i = 2; i < length; i++) {  
            if(i != length-1){  
                dp[i] = Math.max((dp[i-2] + nums[i]),nums[i-1]);  
            }else{  
                dp[i] = Math.max(Math.max((dp[1]+nums[i]),(dp[i-2] + nums[i])),nums[i-1]);  
            }  
        }  
        return dp[length-1];  
    }  
}  
class houseRobber2Test {  
    public static void main(String[] args) {  
        houseRobber2 example = new houseRobber2();  
        int[] nums = {6,2,3,4,5};  
        System.out.println(example.rob(nums));  
    }  
}
```
该版本的问题在于,仍然会输出包含头尾的答案,为解决难点环

decomposition:
环的问题可以拆解为三种情况:
1  6  1  9  1
1)选首元素(舍弃尾元素)
1  6  1  9
2)选尾元素(舍弃首元素)
 6  1  9  1
3)一个都不选(舍弃首尾元素)
6  1  9

情况一和情况二其实囊括了情况三。情况一和情况二的考虑范围都包含了情况三的三个数字。
最终选择情况二和情况三的最大值即可。
>[!Tips] 复制子数组:
> copyOfRange(int[] original, int from, int to)  左闭右开
> 比如本题:
> int[] arr0 = Arrays.copyOfRange(nums, 0, (length - 1));  (去尾)
> int[] arr1 = Arrays.copyOfRange(nums, 1, (length)); (去头)

```java
public class houseRobber2 {  
    public int rob(int[] nums) {  
        if (nums.length == 1) return nums[0];  
        int length = nums.length;  
//        int[] arr0 = Arrays.copyOfRange(nums,0,(length-1));  
//        int[] arr1 = Arrays.copyOfRange(nums,1,(length));  
  
        int rob0 = robbing(Arrays.copyOfRange(nums, 0, (length - 1)));  
        int robL = robbing(Arrays.copyOfRange(nums, 1, (length)));  
  
//        for (int i = 0; i < arr0.length; i++) {  
//            System.out.print("arr0["+i+"] = "+arr0[i] + " ");  
//        }  
//        System.out.println();  
//        for (int i = 0; i < arr1.length; i++) {  
//            System.out.print("arr1["+i+"] = "+arr1[i] + " ");  
//        }  
  
        return Math.max(rob0, robL);  
    }  
  
    public int robbing(int[] nums) {  
        int[] dp = new int[nums.length];  
        if (nums.length == 1) return nums[0];  
  
        dp[0] = nums[0];  
        dp[1] = Math.max(nums[0], nums[1]);  
  
        for (int i = 2; i < dp.length; i++) {  
            dp[i] = Math.max((dp[i - 2] + nums[i]), dp[i - 1]);  
        }  
  
        return dp[nums.length - 1];  
    }  
  
}  
  
class houseRobber2Test {  
    public static void main(String[] args) {  
        houseRobber2 example = new houseRobber2();  
        int[] nums = {2, 4};  
        System.out.println(example.rob(nums));  
    }  
}
```

### 9.24  337. House Robber III
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called root.
Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that all houses in this place form a binary tree. It will automatically contact the police if two directly-linked houses were broken into on the same night.
Given the root of the binary tree, return the maximum amount of money the thief can rob without alerting the police.
https://leetcode.cn/problems/house-robber-iii/description/
337.打家劫舍III  
https://www.bilibili.com/video/BV1H24y1Q7sY

https://programmercarl.com/0337.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DIII.html

二叉树遍历要熟悉!
树形dp的状态转移

1. dp数组的定义
    dp`[0]:不偷当前节点获得的最大金额
    dp`[1]:偷当前节点获得的最大金额
二叉树使用后序遍历,从下往上遍历。

1)  偷当前节点:
int val1 = node. val + leftDp`[0] + rightDp[0]
则不能偷左右节点。取当前节点的值 + 不偷当前节点左节点获得的最大金额 + 不偷当前节点右节点获得的最大金额
2) 不偷当前节点:
int val2 = Math.max(leftDp`[0],leftDp[1]) + Math.max(rightDp[0],rightDp[1]);
return {val2, val1};

```java
public class houseRobber3 {  
    public int rob(TreeNode root) {  
        int[] arr = robbing(root);  
        return Math.max(arr[0],arr[1]);  
    }  
    public int[] robbing(TreeNode node){  
        int[] arr = new int[2];  
        //中  
        //若当前节点为空,则偷不偷都没钱,返回0  
        if(node == null) return arr;  
        //左  
        int[] left = robbing(node.left);  
        //右  
        int[] right = robbing(node.right);  
  
        arr[1] = node.val + left[0] + right[0];//偷当前节点,则返回当前节点金额和不偷左右子节点获得的最大金额  
        arr[0] = Math.max(left[0],left[1]) + Math.max(right[0],right[1]);//不偷当前节点,则返回左右子节点偷/不偷的最大值  
  
        return arr;  
    }  
}
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值