这个题目其实就是 树形结构的 打家劫舍 (隔一家抢一家)
在打家劫舍中,我们是使用dp[i]记录当前的最大值,如果上一家刚抢过,就返回dp[i-2]
而对于这个题目,我们对每个节点记录两个状态,就是抢和没抢的最大值
具体转移方程如下:
dfs(node,rob) 表示对于当前node节点,抢了true或者不抢false的最高金额.
那么如果当前节点抢了,左右孩子就都不能抢了,而如果当前节点不抢,那么就看是抢左右节点好还是不抢好来判断.
边界的nullptr返回0
最后递归到根节点就是返回 max (dfs(root,false),dfs(root,true))
dfs(root,true) = dfs(root->left,false) + dfs(root->right,false)+root->val
dfs(root,false) = max(dfs(root->left,false),dfs(root->left,true)) +
max(dfs(root->right,false),dfs(root->right,true))
代码如下:
这个代码也是灵神的记忆化dfs的模板,可以借鉴学习一下
class Solution {
public:
int rob(TreeNode* root) {
map<pair<TreeNode*,bool>,int> memo; //unordered_map的key 不能是pair 否则要写hash函数
function<int(TreeNode*root,bool choose)> dfs=[&](TreeNode* root,bool choose)->int{
if(!root) return 0;
if(memo.count({root,choose})) return memo[{root,choose}];
int ans=0;
if(choose){
ans=root->val;
ans+=dfs(root->left,false)+dfs(root->right,false);
return ans;
}else{
ans=max(dfs(root->left,true),dfs(root->left,false)) + max(dfs(root->right,true),dfs(root->right,false));
}
memo[{root,choose}]=ans;
return ans;
};
return max(dfs(root,true),dfs(root,false));
}
};