198.打家劫舍
1.dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。
2.有递推公式可知,我们要先定义前面两个值。dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);
3.由于dp[i]是由前面两个推来的,所以遍历要从前到后。
class Solution {
public:
int rob(vector<int>& nums) {
vector<int> dp(nums.size());
if(nums.size()==0) return 0;
if(nums.size()==1) return nums[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
这道题目和上面那题是差不多的,唯一区别就是成环了。
成环就考虑三种情况:
1.不含首尾元素 2.不含首个元素 3.不含尾部元素
第二三种情况包含了第一种情况,所以我们只需处理第二三两种情况就可以了。
处理方法和上题差不多。
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size()==0) return 0;
if(nums.size()==1) return nums[0];
return max(robrange(nums,0,nums.size()-2),robrange(nums,1,nums.size()-1));
}
int robrange(vector<int>& nums,int start,int end){
if (end == start) 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
这题融合了递归三部曲和动规五部曲。(这题很重要)也就是树形DP。
1.终止条件:当root==NULL时,偷与不偷都是0,也相当于初始化。
2.dp数组下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。
3.首先明确的是使用后序遍历。 因为要通过递归函数的返回值来做下一步计算。
class Solution {
public:
int rob(TreeNode* root) {
vector<int> res=traversal(root);
return max(res[0],res[1]);
}
vector<int> traversal(TreeNode *root){
if(root==nullptr) return vector<int> {0,0};
vector<int> left = traversal(root->left);
vector<int> right = traversal(root->right);
int val1 = max(left[0],left[1])+max(right[0],right[1]); //不偷
int val2 = root->val + left[0] + right[0]; //偷
return {val1,val2};
}
};