题目描述

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

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


解题思路:

  1. 环状排列房间问题约化为两个单排排列房间子问题
    1. 在不偷窃第一个房子的情况下[0,n-2],最大金额是 p1
    2. 在不偷窃最后一个房子的情况下[1,n-1],最大金额是 p2
  2. 对两个子问题分别解决.

dp[i]数组定义:在规定区间内偷窃到的最大金额.
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i- 1])

    static int rob(int[] nums) {
        int n = nums.length;
        if (nums == null || nums.length == 0) {
            return 0;
        }
        if (n == 1) {
            return nums[0];
        }
        if (n == 2) {
            return Math.max(nums[0], nums[1]);
        }
        return Math.max(solu(nums, 0, n - 2), solu(nums, 1, n - 1));
    }

    static int solu(int[] nums, int s, int e) {
        int n = nums.length;
        int[] dp = new int[n];
        dp[s] = nums[s];
        dp[s + 1] = Math.max(nums[s + 1], nums[s]);
        for (int i = s + 2; i <= e; i++) {
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i- 1]);
        }
        return dp[e];
    }

踩坑点:

  1. 在指定区间内求解dp数组时,注意数组的起始与结束
dp[s] = nums[s];
dp[s + 1] = Math.max(nums[s + 1], nums[s]);

Q.E.D.