解题思路
两种思想,动态规划和记忆化搜索
1.动态规划
- 动态规划,定义一个数组memo[n+1], 其中memo[0]表示一个店也没有,固定值为0;memo[1]表示洗劫到了第一个店,是固定值,毕竟就一个店,有多少拿多少。注意这里的定义,表示洗劫到了第几个店,当然这个店洗不洗,不一定,至少到这个店了。
- 假如到了第n个店,会有两种情况:
a. 洗劫:那么就要求第n-1个不能洗,于是洗劫值为当前店nums[n] 和 前n-2个店的最大值之和;
b. 不洗劫,那么就是说我要求前n-1个店洗劫最大值,毕竟不洗劫第n个,那么说明第n-1个是允许被洗劫的。 这两种情况求最大的一个就是memo[n] 的值。 - 举一个具体的例子:比如说n = 2; 那么有两种情况:
a. 洗劫第二个店,那么就要求n-1个也就是第一个不能洗劫,于是就是求前n-2个最大值再加上第二个店的值:也就是memo[0] +nums[2]
b. 不洗劫第二个店:那么第一个是可以洗劫的,也可以不洗,所以我们可以求前n-1个的最大值
2. 记忆化搜索
动态规划是自下而上计算,那么记忆化搜索就是自上而下去计算,我们考虑到了第n个店,洗劫还是不洗劫两种情况:若洗,就要用nums[n] 加上前n-2个最大值; 要是不洗,那么就求前n-1个最大值即可。本质和动态规划一样,就是一个自上而下(记忆化搜索),一个自下而上(动态规划)
代码
// 记忆化搜索
class Solution {
private:
vector<int> memo;
int fun(vector<int>& nums, int n) {
if (n == 0) return 0;
if (n == 1) return nums[0];
if (memo[n] == -1) {
memo[n] = max(fun(nums, n-1), nums[n-1] + fun(nums, n-2));
}
return memo[n];
}
public:
int rob(vector<int>& nums) {
memo = vector<int>(nums.size()+1, -1);
return fun(nums, nums.size());
}
};
// 动态规划
class Solution {
private:
vector<int> memo;
int fun(vector<int>& nums) {
memo[0] = 0; // 表示没有店铺
memo[1] = nums[0]; // 第一个店
for (int i = 2; i <= nums.size(); i++) {
int a = memo[i-1];
int b = memo[i-2] + nums[i-1]; // 注意,这里的nums[i-1] 表示第i个店铺,毕竟nums的下标从0开始
memo[i] = a > b ? a : b;
}
return memo[nums.size()];
}
public:
int rob(vector<int>& nums) {
memo = vector<int>(nums.size()+1);
return fun(nums);
}
};