题目描述

描述转载自力扣《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 。

解题思路

  1. 使用动态规划解决此题,我们得先从一个简单的例子着手,比如数组 arr = [2, 1, 1, 2],我们一眼就能看出不相邻的数的最大和是 4,由 arr[1] 与 arr[3] 求和得出。
  2. 我们假设必须算上 arr[3],那么就有两种选择,图片说明图片说明 ,可以得出最大值是后者,结果为 4。
  3. 我们假设必须算上 arr[2],那么我们就只有一个选择 图片说明 结果为 3,比 4 要小,所以最大值依然是 4。
  4. 按照上面的分析可以得出状态转移方程 图片说明 ,要注意因为 dp[0] 和 dp[1] 前面没有不相邻的值,所以 图片说明

Java代码实现

  1. 方法1
class Solution {
    public int rob(int[] nums) {
        if (nums.length == 1) return nums[0];
        else if (nums.length == 2) return Math.max(nums[0], nums[1]);
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = nums[1];
        int max = Math.max(dp[0], dp[1]);

        for (int i = 2; i < nums.length; ++i) {
            int curMax = 0;
            for (int j = i - 2; j >= 0; --j) {
                int cur = nums[i] + dp[j];
                if (curMax < cur) curMax = cur;
            }
            dp[i] = curMax;
            max = Math.max(max, curMax);
        }
        return max;
    }
}
  1. 方法2
class Solution {
    public int rob(int[] nums) {
        if (nums.length == 1) return nums[0];
        else if (nums.length == 2) return Math.max(nums[0], nums[1]);
        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) {
            // 思想:判断加上 nums[i] 后是否是最大的
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[nums.length - 1];
    }
}