- 题目:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 - 示例:
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
3. 思路:
暴力解法:检查所有房子的组合,对每一个组合,检查是否有相邻的房子,如果没有,记录其价值。找最大值。O((2^n)*n) 组合问题
注意其中对状态的定义:
考虑偷取[x…n-1]范围里的房子(函数的定义)
根据对状态的定义,决定状态的转移:
f(0)=max{v(0)+f{2},v(1)+f(3),v(2)+f(4),…,v(n-3)+f(n-1),v(n-2),v(n-1)} (状态转移方程)
4. 代码:
递归求解会超时。
class Solution {
public:
int rob(vector<int>& nums) {
return tryRob(nums,0);
}
private:
//考虑抢劫nums[index,...nums.size()-1]这个范围内的所有房子
int tryRob(vector<int>& nums,int index){
if(index>=nums.size())
return 0;
int res=0;
for(int i=index;i<nums.size();i++)
res=max(res,nums[i]+tryRob(nums,i+2));
return res;
}
};
记忆化搜索:
class Solution {
public:
int rob(vector<int>& nums) {
memo=vector<int>(nums.size(),-1);
return tryRob(nums,0);
}
private:
//memo[i]考虑抢劫nums[i,...nums.size()-1]这个范围内的所有房子能获得的最大收益
vector<int> memo;
int tryRob(vector<int>& nums,int index){
if(index>=nums.size())
return 0;
if(memo[index]!=-1)
return memo[index];
int res=0;
for(int i=index;i<nums.size();i++)
res=max(res,nums[i]+tryRob(nums,i+2));
memo[index]=res;
return res;
}
};
动态规划:
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==0) return 0;
//dp[i]表示考虑抢劫nums[i...n-1]所能获得的最大收益
vector<int> dp(n,-1);
dp[n-1]=nums[n-1];
for(int i=n-2;i>=0;i--)
//dp[i]计算
for(int j=i;j<n;j++)
dp[i]=max(dp[i],nums[j]+(j+2<n?dp[j+2]:0));
return dp[0];
}
};