打家劫舍(一)_牛客题霸_牛客网
描述
你是一个经验丰富的小偷,准备偷沿街的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家,就不能再偷第二家;如果偷了第二家,那么就不能偷第一家和第三家。
给定一个整数数组nums,数组中的元素表示每个房间存有的现金数额,请你计算在不被发现的前提下最多的偷窃金额。
状态:F(i) 表示第i家可以偷取的最大金额
状态转移:F(i) = max(F(i-1), nums[i]+F(i-2))
初始状态: dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
返回结果:dp[n-1]
int rob(vector<int>& nums) {
// write code here
int n = nums.size();
vector<int> dp(n);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for(int i = 2; i<n; i++)
{
dp[i] = max(dp[i-1], dp[i-2]+nums[i]);
}
return dp[n-1];
}
力扣 213. 打家劫舍 II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
针对这个围成一个环状的题目,参考打家劫舍一
状态:F(i) 表示第i家可以偷取的最大金额
状态转移方程:F(i) = max(F(i-1), nums[i]+F(i-2))
这里分为俩种情况:
如果第一家偷了,那么第二家和最后一家就不能偷
① 那么初始化dp[0] = nums[0], dp[1] = max(nums[0], nums[1]);这里注意dp[1]的初始化,因为存在第一个偷了 然后直接连跳俩个房子偷第四个房子,例如下:从第一家直接到第四家。
② 遍历的时候就不用遍历最后一个房间
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for(int i = 2; i < n-1; i++)
dp[i] = max(dp[i-1], nums[i]+dp[i-2]);
int max1 = dp[n-2];
如果第一家选择不偷,那么就把第一间房间去掉,对后面的房子按照打家劫舍一来进行操作(不需要处理dp[0],直接从dp[1],dp[2]开始初始化,也从i=3开始遍历)
dp[1] = nums[1];
dp[2] = max(nums[1], nums[2]);
for(int i = 3; i < n; i++)
dp[i] = max(dp[i-1], nums[i]+dp[i-2]);
int max2 = dp[n-1];
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if(n==1)return nums[0];
if(n==2)return max(nums[0], nums[1]);
vector<int> dp(n);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for(int i = 2; i < n-1; i++)
dp[i] = max(dp[i-1], nums[i]+dp[i-2]);
int max1 = dp[n-2];
dp[1] = nums[1];
dp[2] = max(nums[1], nums[2]);
for(int i = 3; i < n; i++)
dp[i] = max(dp[i-1], nums[i]+dp[i-2]);
int max2 = dp[n-1];
return max1>max2?max1:max2;
}
};