Problem_link: 213. 打家劫舍 II
前言
偷东西是不对的
思路
思路和打家劫舍普通差不多,只是多了一个头尾不能同时偷的条件,既然这样,就遍历两次,第一次不管第一家,第二次不管最后一家。
解题方法
- 边界
l e n ( n u m s ) < = 3 len(nums)<=3 len(nums)<=3时,只能选一家,所以挑最大的选就行了。代码是可以处理2家以上的情况的,这样直接返回略快一些。
- 定义状态
每家我们都有偷和不偷两种情况:
- 如果偷,它的前一家就不能偷,结果就等于前一家不偷的情况加上这家的金额。
- 如果不偷,结果就是前一家偷和前一家不偷两种情况中的最大值。
所以, d p [ i ] [ 0 o r 1 ] dp[i][0\ or\ 1] dp[i][0 or 1]表示第i+1家(i从0开始)偷(1)和不偷(0)两种情况的最优解。
{ d p [ 0 ] [ 0 ] = 0 第一家不偷 d p [ 0 ] [ 1 ] = n u m s [ 0 ] 第一家偷 d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] ) 不偷这一家 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + n u m s [ i ] 偷这一家 \begin{cases} dp[0][0] = 0 & 第一家不偷 \\ dp[0][1] = nums[0]& 第一家偷 \\ dp[i][0] = max(dp[i-1][1],dp[i-1][0])& 不偷这一家 \\ dp[i][1] = dp[i-1][0]+nums[i] & 偷这一家 \end{cases} ⎩ ⎨ ⎧dp[0][0]=0dp[0][1]=nums[0]dp[i][0]=max(dp[i−1][1],dp[i−1][0])dp[i][1]=dp[i−1][0]+nums[i]第一家不偷第一家偷不偷这一家偷这一家
- 首尾问题
遍历两次,让首尾不同时出现就可以解决。 - 最终结果
把两次遍历的结果都做最大值比较,结果就出来了。
复杂度
-
时间复杂度:
O ( n ) O(n) O(n) -
空间复杂度:
O ( n ) O(n) O(n)
Code
int max(int a,int b){
return a>b?a:b;
}
// 偷家范围
int robRange(int* nums, int start, int end) {
// 对第i个房子偷和不偷,0是不偷,1是偷
int dp[100][2] = {{0}};
dp[start][0] = 0;
dp[start][1] = nums[start];
for (int i = start+1; i < end; i++) {
dp[i][0] = max(dp[i-1][0],dp[i-1][1]);
dp[i][1] = dp[i-1][0]+nums[i];
}
return max(dp[end-1][0],dp[end-1][1]);
}
int rob(int* nums, int numsSize){
// 边界
if(numsSize<=3){
int res = nums[0];
for(int i=1;i<numsSize;i++){
res = max(res,nums[i]);
}
return res;
}
// 不管第一家的结果和不管最后一家的结果进行比较
return max(robRange(nums,1,numsSize),robRange(nums,0,numsSize-1));
}
可以发现每次只使用上一次偷家状态
,所以可以将空间优化为常量。
class Solution:
def rob(self, nums: List[int]) -> int:
# 边界
if(len(nums)<=3):
return max(nums)
def robRange(nums: List[int],start,end) ->int:
# 偷上一家
stealFami = nums[start]
# 不偷上一家
notstealFami= 0
# 偷这一家
notstealThisFami=None
# 不偷这一家
stealThisFami =None
for i in range(start+1,end):
notstealThisFami = max(stealFami,notstealFami)
stealThisFami = notstealFami+nums[i]
stealFami,notstealFami = stealThisFami,notstealThisFami
return max(stealFami,notstealFami)
return max(robRange(nums,1,len(nums)),robRange(nums,0,len(nums)-1))