题目
一条环形街道上有若干房屋。输入一个数组表示该条街道上的房屋内财产的数量。如果这条街道上相邻的两幢房屋被盗就会自动触发报警系统。请计算小偷在这条街道上最多能偷取的财产的数量。例如,街道上5家的财产用数组[2,3,4,5,3]表示,如果小偷到下标为1和3的房屋内盗窃,那么他能偷取到价值为8的财物,这是他在不触发报警系统的情况下能偷取到的最多的财物
分析
由于这个问题和面试题89的区别在于小偷不能同时到标号为0和n-1的两幢房屋内偷东西。如果他考虑去标号为0的房屋,那么他一定不能去标号为n-1的房屋;如果他考虑去标号为n-1的房屋,那么他一定不能去标号为0的房屋。因此,可以将这个问题分解成两个子问题:一个问题是求小偷从标号为0开始到标号为n-2结束的房屋内能偷得的最多财物数量,另一个问题是求小偷从标号为1开始到标号为n-1结束的房屋内能偷得的最多财物数量。小偷从标号为0开始到标号为n-1结束的房屋内能偷得的最多财物数量是这两个子问题的解的最大值。
解
public class Test {
public static void main(String[] args) {
int[] cost = {2, 3, 4, 5, 3};
int result = rob(cost);
System.out.println(result);
}
public static int rob(int[] nums) {
if (nums.length == 0) {
return 0;
}
if (nums.length == 1) {
return nums[0];
}
int result1 = helper(nums, 0, nums.length - 2);
int result2 = helper(nums, 1, nums.length - 1);
return Math.max(result1, result2);
}
private static int helper(int[] nums, int start, int end) {
int[] dp = new int[2];
dp[0] = nums[start];
if (start < end) {
dp[1] = Math.max(nums[start], nums[start + 1]);
}
for (int i = start + 2; i <= end; i++) {
int j = i - start;
dp[j % 2] = Math.max(dp[(j - 1) % 2], dp[(j - 2) % 2] + nums[i]);
}
return dp[(end - start) % 2];
}
}