代码随想录第39天|leetcode198.打家劫舍、leetcode213.打家劫舍II 、leetcode337.打家劫舍III
1.198. 打家劫舍 - 力扣(LeetCode)
当前房屋偷与不偷取决于前一个房屋和前两个房屋是否被偷,所以就可以得到相应的dp数组。
即,dp[i] = max(dp[i-2]+nums[i],dp[i-1]);
int rob(vector<int>& nums) {//dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。if (nums.size() == 0) return 0;if(nums.size() ==1) return nums[0];vector<int> dp(nums.size());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];}
2.213. 打家劫舍 II - 力扣(LeetCode)
对于一个数组,成环的话主要有如下三种情况:
- 情况一:考虑不包含首尾元素
- 情况二:考虑包含首元素,不包含尾元素
- 情况三:考虑包含尾元素,不包含首元素
这里有个点:对于情况2或者情况3,从第一个或者最后一个开始遍历,但是不一定要选第一个或者最后一个。
int rob(vector<int>& nums) {if(nums.size()==0)return 0;if(nums.size()==1)return nums[0];if(nums.size()==2)return max(nums[0],nums[1]);int result1=robRange(nums,0,nums.size()-2);//不偷最后一个int result2=robRange(nums,1,nums.size()-1);//不偷第一个return max(result1,result2);}int robRange(vector<int>& nums,int start,int end){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];}
3.337. 打家劫舍 III - 力扣(LeetCode)树形DP
所以dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。
思路:首先将根节点传入函数,如果当前节点为空,返回<0,0>,然后进行二叉树的后序遍历。自底向上进行遍历,分两种情况讨论,如果偷取cur,那么就不偷左右节点。如果偷取cur,那么偷取较大的左右节点,代码如下所示。一刷本题,有点难度啊。。。。
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 == nullptr)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};}