198. House Robber I / House Robber III

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 system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

思路

  1. 根据题目,因为不能连续偷两家,所以:有两种可能,偷当前家可以最大获利,或者不偷当前家可以最大获利。
  2. 偷当前家的最大获利 = max(【偷上一家的再上一家的maxProfit + 当前家的财产】,不偷当前家(即偷上一家的最大获利))
  3. 用DP,dp[i] 表示偷第i家获得的最大利益
  4. 初始化时,必须初始化dp[0], dp[1], 因为在求dp[i]的时候,我们必须知道偷上一家和偷上上家的获利。所以循环只能从2开始。0和1必须被初始化。
class Solution {
    public int rob(int[] nums) {
        //用DP
        //因为不能连续偷两家,所以:有两种可能,偷当前价可以最大获利,或者不偷当前价可以最大获利
        //偷当前家的最大获利 = max(【偷上一家的再上一家的maxProfit + 当前家的财产】,不偷当前家(即偷上一家的最大获利))
        //dp[i]: 偷第i家的最大获利
        
        if (nums == null || nums.length == 0) return 0;
        if (nums.length == 1) return nums[0];
        if (nums.length == 2) return Math.max(nums[0], nums[1]);
        
        int[] dp = new int[nums.length];
        //循环只能从2开始,因为必须知道上一家 和 上上一家偷的情况
        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];
    }
}

House Robber III

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "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 forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.

Example 1:

     3
    / \
   2   3
    \   \ 
     3   1

Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

Example 2:

     3
    / \
   4   5
  / \   \ 
 1   3   1

Maximum amount of money the thief can rob = 4 + 5 = 9.

思路 (递归)

与1思路相同,对于每个节点小偷都可以选择偷或者不偷,那么对每个节点都返回一个int[2], result[0]表示偷这家能获取的最大利益,result[1]表示不偷这家能获取的最大利益。

  1. DFS搜索:递归停止条件,root == null 时返回new int[2]:表示偷与不偷的获利都为0.
  2. DFS计算其left和right child的获利结果。
  3. 当前节点偷(那么左右节点都不能偷): cur.val + leftProfit[1] + rightProftit[1]。
  4. 当前节点不偷(左右节点可以偷, 也可以不偷):Max(leftProfit[0], leftProfit[1]) + Max(rightProfit[0], rightProfit[1])
  5. 最后返回root节点偷或者不偷的最大值即可
class TreeNode {
  int val;
  TreeNode left;
  TreeNode right;
  
  public TreeNode(int val) {
    this.val = val;
    this.left = null;
    this.right = null;
  }
}


class Solution{
  static public int rob(TreeNode root) {
    if (root == null) return 0;
    
    int[] result = helper(root);
    return Math.max(result[0], result[1]);
  }
  
  static public int[] helper(TreeNode root) {
    if (root == null) {
      return new int[2];
    }
    
    // index 0: rob, index 1: not rob
    int[] leftProfit = helper(root.left);
    int[] rightProfit = helper(root.right);
    int[] result = new int[2];
    
    // rob: cannot rob the neighbor
    result[0] = root.val + leftProfit[1] + rightProfit[1];
    
    // not rob: can rob the neighbor, or not rob the neighbor; choose the bigger profit
    result[1] = Math.max(leftProfit[0], leftProfit[1]) + Math.max(rightProfit[0], rightProfit[1]);
    
    return result;
  }
  
  public static void main(String[] args) {
    TreeNode root = new TreeNode(3);
    TreeNode n1 = new TreeNode(2);
    TreeNode n2 = new TreeNode(3);
    root.left = n1;
    root.right = n2;
    
    TreeNode n3 = new TreeNode(4);
    TreeNode n4 = new TreeNode(5);
    
    n1.left = n3;
    n1.right = n4;
    
    TreeNode n5 = new TreeNode(1);
    n2.right = n5;
    
    System.out.println(rob(root));
    
  }
}

你可能感兴趣的:(198. House Robber I / House Robber III)