198.打家劫舍
题目链接:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
求解思路:
当前房屋偷与不偷取决于前一个房屋是否被偷了
动规五部曲
- 确定dp数组及其下标含义:考虑下标i(包括i)以内的房屋,最多可以偷的金额为dp[i]
- 确定递归公式:如果前一个屋子被抢了,那么现在这间屋子不能抢,即dp[i] = dp[i-1];如果前一间屋子没被抢,那么这件屋子可以抢,即dp[i] = dp[i - 2] + nums[i];取较大值,dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
- dp数组的初始化:递推公式的基础为dp[0]和dp[1],从定义中可以得到dp[0] = nums[0],dp[1] = max(nums[0], nums[1]);
- 确定遍历顺序:dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,从前到后遍历
- 举例推导dp数组:以[2,7,9,3,1]为例,如图
代码:
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[0];
vector<int> dp(nums.size(), 0);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for (int i = 2; i < nums.size(); i++){
dp[i] = max(dp[i-2]+nums[i], dp[i-1]);
}
return dp[nums.size()-1];
}
};
213.打家劫舍II
题目链接:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
求解思路:
分成两种情况,一种是不包含头元素,一种是不包含尾元素,取较大值即可。
求解思路与上一题一样。
代码:
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[0];
int r1 = robRange(nums, 0, nums.size()-2);
int r2 = robRange(nums, 1, nums.size()-1);
return max(r1, r2);
}
int robRange(vector<int>& nums, int start, int end){
if (start == end) return nums[start];
vector<int> dp(nums.size());
dp[start] = nums[start];
dp[start+1] = max(nums[start], nums[start+1]);
for (int i = start+2; i <= end; i++){
dp[i] = max(dp[i-2]+nums[i], dp[i-1]);
}
return dp[end];
}
};
337.打家劫舍III
题目链接:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
求解思路:
使用一个长度为2的数组,记录当前节点偷和不偷所得到的最大金钱
递归+动规
- 确定递归函数的参数和返回值:参数为当前节点,返回值为一个长度为2的数组;其中数组下标为0记录不偷该节点所得到的最大金钱,下标为1记录偷该节点所得到的最大金钱
- 确定终止条件:遇到空间点,无论偷还是不偷都是0,返回
- 确定遍历顺序:后序遍历二叉树,因为要通过递归函数的返回值来做下一步计算
- 确定单层递归逻辑:如果偷当前节点,则左右孩子都不能投,此时val1 = cur->val + left[0] + right[0];如果不偷当前节点,则左右孩子可偷可不偷,取较大的值,此时val2 = max(left[0], left[1]) + max(right[0], right[1]);注意最后返回{val2, val1},即{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}
- 举例推导dp数组:以示例1为例,如图
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int rob(TreeNode* root) {
vector<int> result = robTree(root);
return max(result[0], result[1]);
}
// 长度为2的数组,0表示不偷,1表示偷
vector<int> robTree(TreeNode * cur){
if (cur == NULL) return vector<int>{0,0};
vector<int> left = robTree(cur->left);
vector<int> right = robTree(cur->right);
// 偷cur,则不能偷其左右孩子
int val1 = cur->val + left[0]+ right[0];
// 不偷cur,则左右孩子可偷可不偷,取较大值
int val2 = max(left[0], left[1]) + max(right[0], right[1]);
// 注意这里的返回顺序不可以错
return {val2, val1};
}
};