• LeetCode刷题day48|198.打家劫舍、213.打家劫舍Ⅱ、337.打家劫舍Ⅲ


    一、198.打家劫舍

    需要注意的点:

    1. dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。
    2. 决定dp[i]的因素就是第i房间偷还是不偷。
      如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。
      如果不偷第i房间,那么dp[i] = dp[i - 1],即考虑i-1房,(注意这里是考虑,并不是一定要偷i-1房,这是很多同学容易混淆的点)
    3. 从递推公式dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);可以看出,递推公式的基础就是dp[0] 和 dp[1]
      从dp[i]的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);
      然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])

    以下是代码部分:

    public class 打家劫舍198 {
    
        public int rob(int[] nums) {
    
            //踩坑,没有看数组的长度范围
            if(nums.length == 1)
                return nums[0];
    
            //dp数组,表示i之前(包括i)的最大金额
            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];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    二、213.打家劫舍Ⅱ

    需要注意的点:
    由于第一个和最后一个只能考虑其中一个,所以将总的情况分成两个大情况( 将环形问题转换为直线型问题 ):

    1. 不考虑最后一个
    2. 不考虑第一个

    没有第三种情况,所以两种情况的最大值就是最终解。

    以下是代码部分:

    public class 打家劫舍Ⅱ213 {
    
        public int rob(int[] nums) {
    
            if(nums.length == 1)
                return nums[0];
    
            int zero = solve(nums, 0, nums.length-1);
            int one = solve(nums, 1, nums.length);
    
            return Math.max(zero, one);
        }
    
        private int solve(int[] nums, int start, int end){
    
            int[] dp = new int[end - start];
    
            dp[0] = nums[start];
    
            //踩坑:这里dp也有可能长度为1,所以也要记得判断
            if(dp.length == 1)
                return dp[0];
    
            dp[1] = Math.max(nums[start], nums[start+1]);
    
            for (int i = 2; i < dp.length; i++) {
                //注意:nums[]中是 i+start (如果 i 等于1,相当于整体向右挪了一位)
                dp[i] = Math.max(dp[i-2] + nums[i + start], dp[i-1]);
            }
    
            return dp[dp.length-1];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    三、337.打家劫舍Ⅲ

    其实与第一道题类似,不同点在于是遍历节点的方式。
    需要注意的点:

    1. 必须使用后序遍历
    2. 需要记录孙子节点的信息。有两种方式:①使用map哈希表记录当前节点对应的最大金额,防止需要不停地调用;②递归函数的返回值可以存放两个数,一个数是不包含当前节点的最大金额(即孙子节点的信息记录在这里),另一个数是包含当前节点的最大金额。这里并没有取一个最大值,取最大值的操作交给了父亲节点。

    以下是代码部分:

    class Solution {
        // 1.递归去偷,超时
        public int rob(TreeNode root) {
            if (root == null)
                return 0;
            int money = root.val;
            if (root.left != null) {
                money += rob(root.left.left) + rob(root.left.right);
            }
            if (root.right != null) {
                money += rob(root.right.left) + rob(root.right.right);
            }
            return Math.max(money, rob(root.left) + rob(root.right));
        }
    
        // 2.递归去偷,记录状态
        // 执行用时:3 ms , 在所有 Java 提交中击败了 56.24% 的用户
        public int rob1(TreeNode root) {
            Map<TreeNode, Integer> memo = new HashMap<>();
            return robAction(root, memo);
        }
    
        int robAction(TreeNode root, Map<TreeNode, Integer> memo) {
            if (root == null)
                return 0;
            if (memo.containsKey(root))
                return memo.get(root);
            int money = root.val;
            if (root.left != null) {
                money += robAction(root.left.left, memo) + robAction(root.left.right, memo);
            }
            if (root.right != null) {
                money += robAction(root.right.left, memo) + robAction(root.right.right, memo);
            }
            int res = Math.max(money, robAction(root.left, memo) + robAction(root.right, memo));
            memo.put(root, res);
            return res;
        }
    
        // 3.状态标记递归
        // 执行用时:0 ms , 在所有 Java 提交中击败了 100% 的用户
        // 不偷:Max(左孩子不偷,左孩子偷) + Max(又孩子不偷,右孩子偷)
        // root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) +
        // Math.max(rob(root.right)[0], rob(root.right)[1])
        // 偷:左孩子不偷+ 右孩子不偷 + 当前节点偷
        // root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
        public int rob3(TreeNode root) {
            int[] res = robAction1(root);
            return Math.max(res[0], res[1]);
        }
    
        int[] robAction1(TreeNode root) {
            int res[] = new int[2];
            if (root == null)
                return res;
    
            int[] left = robAction1(root.left);
            int[] right = robAction1(root.right);
    
            res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
            res[1] = root.val + left[0] + right[0];
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    Ubuntu22.0.4安装svn服务
    Vue / Vue指令、事件修饰符、事件参数
    MySQL 性能调优和优化技巧
    【Vue3】解决电脑分辨率125%、150%及缩放导致页面变形的问题
    C语言实现冒泡排序、选择排序、快速排序
    阿里云云主机免费试用三个月
    虚拟机macos安装brew、llvm并使用cmake构建项目
    过滤器、监听器、拦截器的区别,你都搞懂了吗?
    static学习
    算法导论24章单源最短路径—Bellman-Ford算法 Dijkstra算法
  • 原文地址:https://blog.csdn.net/weixin_46081231/article/details/127741518