打家劫舍

198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。
public class Onehundred_ninetyEight {
    //dp[i]表示0-i所取得的最大值
    public int rob(int[] nums) {
        int len = nums.length;
        if (len <= 1)
            return len == 0 ? 0 : nums[0];
        int[] dp = new int[len];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < len; ++i)
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
        return dp[len - 1];
    }
}
class Solution {
public:
    int rob(vector<int> &nums) {
        if (nums.empty())
            return 0;
        if (nums.size() <= 2)
            return *max_element(nums.begin(), nums.end());
        vector<int> dp(nums.size());
        dp[0] = nums[0];
        dp[1] = *max_element(nums.begin(), nums.begin() + 2);
        for (int i = 2; i < nums.size(); i++) {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp.back();
    }
};

213. 打家劫舍 II

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。
public class Twohundred_thirteen {
    /**
     * 分为:偷第一家[0,n-2] 和 不偷第一家[1,n-1]
     **/
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0)
            return 0;
        if (nums.length == 1)
            return nums[0];
        int len = nums.length;
        int max = Math.max(helper(Arrays.copyOfRange(nums, 0, len - 1)), helper(Arrays.copyOfRange(nums, 1, len)));
        return max;
    }

    public int helper(int[] nums) {
        int len = nums.length;
        if (len <= 1)
            return len == 0 ? 0 : nums[0];
        int[] dp = new int[len];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < len; ++i)
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
        return dp[len - 1];
    }
}
class Solution {
public:
    int rob(vector<int> &nums) {
        if (nums.empty())
            return 0;
        if (nums.size() <= 3)
            return *max_element(nums.begin(), nums.end());
        vector<int> front_nums(nums.begin(), nums.end() - 1);
        vector<int> back_nums(nums.begin() + 1, nums.end());
        return max(helper(front_nums), helper(back_nums));
    }

    int helper(vector<int> &nums) {
        if (nums.empty())
            return 0;
        if (nums.size() <= 2)
            return *max_element(nums.begin(), nums.end());
        vector<int> dp(nums.size());
        dp[0] = nums[0];
        dp[1] = *max_element(nums.begin(), nums.begin() + 2);
        for (int i = 2; i < nums.size(); i++) {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp.back();
    }
};

337. 打家劫舍 III

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:

输入: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

输出: 7 
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.
示例 2:

输入: [3,4,5,1,3,null,1]

     3
    / \
   4   5
  / \   \ 
 1   3   1

输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.
public class Threehundred_thirtySeven {
    /**
     * 能盗取的最高金额为:max(抢劫该节点+抢劫该节点的左孩子的左右子树+抢劫该节点的右孩子的左右子树, 抢劫该节点的左子树+抢劫该节点的右子树)
     */
    private Map<TreeNode, Integer> sums = new HashMap<>();

    public int rob(TreeNode root) {
        return helper(root);
    }

    public int helper(TreeNode node) {
        if (node == null)
            return 0;
        if (sums.containsKey(node))
            return sums.get(node);
        int val1 = node.val;
        if (node.left != null)
            val1 += helper(node.left.left) + helper(node.left.right);
        if (node.right != null)
            val1 += helper(node.right.left) + helper(node.right.right);
        int val2 = helper(node.left) + helper(node.right);
        sums.put(node, Math.max(val1, val2));
        return sums.get(node);
    }
}
class Solution {
    /**
     * max(抢劫该节点+抢劫该节点的左孩子的左右子树+抢劫该节点的右孩子的左右子树, 抢劫该节点的左子树+抢劫该节点的右子树)
     */
private:
    unordered_map<TreeNode *, int> sum;
public:
    int rob(TreeNode *root) {
        return helper(root);
    }

    int helper(TreeNode *node) {
        if (!node)
            return 0;
        if (sum.count(node))
            return sum[node];
        int val1 = node->val;
        if (node->left)
            val1 += helper(node->left->left) + helper(node->left->right);
        if (node->right)
            val1 += helper(node->right->left) + helper(node->right->right);
        int val2 = helper(node->left) + helper(node->right);
        sum[node] = max(val1, val2);
        return sum[node];
    }
};

return the last

0