dp问题描述
打家劫舍2
这个题和打家劫舍一的最大区别就在于,他的数组是一个环形数组,首尾是相连的,因此如果我们不允许小偷去偷两个相邻的房屋,那么第一个和最后一个房屋,也是不能同时偷的!
因此这个题的解题关键就在于对第一个房子偷不偷进行分类讨论。
- 假如说我偷了第一个房子,那么我最后一个房子以及第二个房子就不能偷了。剩余的房子随便偷(按照打家劫舍1的模型计算出从第三个房子到倒数第二个房子中偷到的最高金额)
- 如果我没有投第一个话,那么其余的房子随便投(按照打家劫舍1的模型计算出从第二个房子到最后一个房子中偷到的最高金额)

确定本题的状态表示
dp[i] 表示:从dp[0]这个房子到dp[i]这个房子偷到的最高金额(从dp[0~i]这一子序列中偷到的最高金额)
我们根据最后一个房子偷或者不偷继续细化:
{ f [ i ] 表示:选择到 i 位置的时候,选择 n u m s [ i ] ,此时子序列中偷到的最高金额 g [ i ] 表示:选择到 i 位置的时候,不选 n u m s [ i ] ,此时子序列中偷到的最高金额 \begin{cases} f[i] 表示:选择到 i 位置的时候,选择nums[i] ,此时子序列中偷到的最高金额 \\ g[i] 表示:选择到 i 位置的时候,不选nums[i] ,此时子序列中偷到的最高金额 \end{cases} {f[i]表示:选择到i位置的时候,选择nums[i],此时子序列中偷到的最高金额g[i]表示:选择到i位置的时候,不选nums[i],此时子序列中偷到的最高金额
确定本题的状态转移方程
依然是
f[i]=g[i-1]+nums[1]
g[i]=max(f[i-1],g[i-1])
填表求值
根据初始条件和状态转移方程,确定填表顺序,进而逐步填满dp表,最终返回题目要的结果
代码实现
class Solution {
public:
int rob1(vector<int>& nums) {
int n=nums.size();
if(n==0) return 0;
vector<int> f(n),g(n);
f[0]=nums[0];g[0]=0;
for(int i=1;i<n;i++){
f[i]=g[i-1]+nums[i];
g[i]=max(f[i-1],g[i-1]);
}
return max(g[n-1],f[n-1]);
}
int rob(vector<int>& nums) {
if(nums.size()==1) return nums[0];
if(nums.size()==2) return max(nums[0],nums[1]);
vector<int> nums1(nums.begin()+1,nums.end());
vector<int> nums2(nums.begin()+2,nums.end()-1);
return max(rob1(nums1),rob1(nums2)+nums[0]);
}
};
273

被折叠的 条评论
为什么被折叠?



