一、题目描述
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000
二、解题思路
根据题目要求,如何才能保证第一间房屋和最后一间房屋不同时偷窃呢?如果偷窃了第一间房屋,则不能偷窃最后一间房屋,因此偷窃房屋的范围是第一间房屋到最后第二间房屋;如果偷窃了最后一间房屋,则不能偷窃第一间房屋,因此偷窃房屋的范围是第二间房屋到最后一间房屋。
假设数组nums
的长度为 n
。如果不偷窃最后一间房屋,则偷窃房屋的下标范围是 [0, n-2]
;如果不偷窃第一间房屋,则偷窃房屋的下标范围是 [1, n-1]
。在确定偷窃房屋的下标范围之后,即可用我的61_打家劫舍
的方法解决。对于两段下标范围分别计算可以偷窃到的最高总金额,其中的最大值即为在 n
间房屋中可以偷窃到的最高总金额。
假设偷窃房屋的下标范围是 [start,end]
,用 dp[i]
表示在下标范围 [start,i]
内可以偷窃到的最高总金额,那么就有如下的状态转移方程:
dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1])
三、代码演示
class Solution {
public int rob(int[] nums) {
//特判
if(nums==null || nums.length==0){
return 0;
}
//当只有一件房子时候,就偷它
if(nums.length == 1){
return nums[0];
}
//根据不同情况传参
//情况一:不偷窃最后一件房屋的范围
int result1 = robRange(nums, 0, nums.length-2);
//情况二:不偷窃第一件房屋
int result2 = robRange(nums, 1, nums.length-1);
return Math.max(result1, result2);
}
//下面这个方法根据传的参数不同进行不同计算
public int robRange(int[] nums, int start, int end){
if(end==start){
return nums[start];
}
//声明dp
int[] dp = new int [nums.length+1];
//dp初始化
dp[start] = nums[start];
dp[start+1] = Math.max(nums[start],nums[start+1]);
//遍历
for(int i=start+2; i<=end; i++){
dp[i] = Math.max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[end];
}
}