第48天 Dynamic Programming House Robber 198、213、337

198. House Robber

  • dp[i]: 0到i家最大可以偷的金额
  • 公式:dp[i] = Math.max(dp[i-2]+nums[i], dp[i-1]) 因为题目说了只要不相邻就可以
  • 注意dp[i-1]不代表nums[i]一定加进来了(不代表i家一定被偷了)
  • 注意dp[i-2]表示0到i-2家最大可以偷的金额,i-2家不一定被偷了
  • 初始化:dp[0] = nums[0]; dp[1] = Math.max(nums[0], nums[1])
  • Time Complexity: O(nums.length)
  • Space Complexity: O(nums.length) -> 优化为O(1)
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-1], dp[i-2]+nums[i]);
        }
        return dp[nums.length-1];
    }
}

213. House Robber ii

  • 考虑去尾,考虑去头,选max
  • Time Complexity: O(nums.length)
  • Space Complexity: O(nums.length) -> 优化为O(1)
// O(1)
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]);

        // int[] dp1 = new int[nums.length-1];
        int dp1first = nums[0];
        int dp1second = Math.max(nums[0], nums[1]);
        for (int i=2; i<nums.length-1; i++) {
            int temp = dp1second;
            dp1second = Math.max(dp1first+nums[i], dp1second);
            dp1first = temp;
        }

        //int[] dp2 = new int[nums.length-1];
        int dp2first = nums[1];
        int dp2second = Math.max(nums[1], nums[2]);
        for (int i=3; i<nums.length; i++) {
            int temp = dp2second;
            dp2second = Math.max(dp2first+nums[i], dp2second);
            dp2first = temp;
        }

        return Math.max(dp1second, dp2second);
    }
}

// O(n)
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]);

        int[] dp1 = new int[nums.length-1];
        dp1[0] = nums[0];
        dp1[1] = Math.max(nums[0], nums[1]);
        for (int i=2; i<nums.length-1; i++) {
            dp1[i] = Math.max(dp1[i-2]+nums[i], dp1[i-1]);
        }

        int[] dp2 = new int[nums.length-1];
        dp2[0] = nums[1];
        dp2[1] = Math.max(nums[1], nums[2]);
        for (int i=3; i<nums.length; i++) {
            dp2[i-1] = Math.max(dp2[i-3]+nums[i], dp2[i-2]);
        }

        return Math.max(dp1[nums.length-2], dp2[nums.length-2]);
    }
}

337. House Robber iii

  • 最佳方法1: dp,状态标记递归
  • dp[i][0] = 第i个node偷的最大值;dp[i][1] = 第i个node不偷的最大值
  • 初始化:i=null, dp[root] = [0,0]
  • 公式:dp[i][0] = root(第i个node).val + dp[root.left][1] + dp[root.right] + 1; dp[i][1] = Math.max(dp[root.left][0], dp[root.left][1]) + Math.max(dp[root.right[0], dp[root.right][1])
  • 注意这里可以体现house robber所有问题都一样的地方,对于可以偷的第i个元素,并不代表一定要偷这第i个元素,而是应该Math.max(偷第i个元素,不偷第i个元素);
  • 遍历顺序:PostOrder后序,需要left child, right child的结果来给出root的结果
  • Time Complexity: O(n),每个节点只遍历了一次
  • Space Complexity: O(log n),算上递推系统栈的空间
class Solution {
    public int rob(TreeNode root) {
        return Math.max(helper(root)[0], helper(root)[1]);
    }

    public int[] helper(TreeNode root) {
        // 0: steal 1: not steal
        if (root == null) return new int[]{0,0};
        int[] left = helper(root.left);
        int[] right = helper(root.right);
        int steal = root.val + left[1] + right[1];
        int notsteal = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        return new int[]{steal, notsteal};
    }
}

  • 方法2: 仅仅recursion递归去偷,超时
class Solution {
    public int rob(TreeNode root) {
        if (root == null) return 0;
        int steal = root.val;
        if (root.left != null)
            steal += rob(root.left.left) + rob(root.left.right);
        if (root.right != null)
            steal += rob(root.right.left) + rob(root.right.right);
        return Math.max(steal, rob(root.left)+rob(root.right));
    }
}
  • 方法3: recursion递归去偷,memo记录状态
  • 提前结束递归,用memo记录过的值:if (map.containsKey(root)) return map.get(root);
class Solution {
    public int rob(TreeNode root) {
        return helper(root, new HashMap<TreeNode, Integer>());
    }
    public int helper(TreeNode root, Map<TreeNode, Integer> map) {
        if (root == null) return 0;
        if (map.containsKey(root)) return map.get(root);
        int steal = root.val;
        if (root.left != null)
            steal += helper(root.left.left, map) + helper(root.left.right, map);
        if (root.right != null)
            steal += helper(root.right.left, map) + helper(root.right.right, map);
        int max = Math.max(steal, helper(root.left, map)+helper(root.right, map));
        map.put(root, max);
        return max;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值