打家劫舍
題目連結:198. 打家劫舍 - 力扣(LeetCode)
思路:每一家的最大收益來源只有兩個,一個是這家不偷,那麼最大收益等於從上一家出來的最大收益,另一個是偷這一個家,因此最大收益等於從上上一家出來的最大收益加這一家的收益。
class Solution {
public:
int rob(vector<int>& nums) {
vector<int>dp(nums.size()+1,0);
dp[0]=0;
dp[1]=nums[0];
for(int i=2;i<=nums.size();i++){
dp[i]=max(dp[i-1],dp[i-2]+nums[i-1]);
}
return dp.back();
}
};
打家劫舍II
題目連結: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 result1=R(nums,0,nums.size()-2);
int result2=R(nums,1,nums.size()-1);
return max(result1,result2);
}
int R(vector<int>& nums,int start,int end){
if(start==end)return nums[start];
vector<int> dp(nums.size(),0);
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-1],dp[i-2]+nums[i]);
}
return dp[end];
}
};
打家劫舍III
題目連結:337. 打家劫舍 III - 力扣(LeetCode)
思路:這一題讓我想到了放攝像頭那一題,總之不會。
遞迴法,也是我一開始想到的做法:
class Solution {
public:
unordered_map<TreeNode* , int> umap; // 記錄計算過的結果
int rob(TreeNode* root) {
if (root == NULL) return 0;
if (root->left == NULL && root->right == NULL) return root->val;
if (umap[root]) return umap[root]; // 如果umap裡已經有記錄則直接返回
// 偷父節點
int val1 = root->val;
if (root->left) val1 += rob(root->left->left) + rob(root->left->right); // 跳過root->left
if (root->right) val1 += rob(root->right->left) + rob(root->right->right); // 跳過root->right
// 不偷父節點
int val2 = rob(root->left) + rob(root->right); // 考慮root的左右孩子
umap[root] = max(val1, val2); // umap記錄一下結果
return max(val1, val2);
}
};
動態規劃法:
對於樹形dp,dp陣列的長度是2,因為我們有遞迴的過程,每個dp陣列只需儲存偷或不偷的最大收益。
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};
}
};