The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night. Determine the maximum amount of money the thief can rob tonight without alerting the police. Example 1: 3 / 2 3 \ \ 3 1 Maximum amount of money the thief can rob = 3 + 3 + 1 = 7. Example 2: 3 / \ 4 5 / \ \ 1 3 1 Maximum amount of money the thief can rob = 4 + 5 = 9. /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
分析:
对于当前根r来说:
a)抢劫当前根节点r,则最大利益为,r->val,rob(r->left->left),rob(r->left->right),rob(r->right->left),rob(r->right->right),这5项的和,如果r的左或者右孩子为null,则跳过该项
b)不抢劫当前r节点,则可以抢劫其左、右孩子节点:rob(r->left)+rob(r->right);
取这两个的最大值为抢劫到当前节点的最大利益。
int dfs(TreeNode *root){ if(root!=NULL) { int robed=root->val; if(root->left){ robed+=(dfs(root->left->left)+dfs(root->left->right)); } if(root->right){ robed+=(dfs(root->right->left)+dfs(root->right->right)); } int nonrobed=dfs(root->left)+dfs(root->right); return max(robed,nonrobed); } return 0; } int rob(TreeNode* root) { return dfs(root); }
但这种情况部分数据会出现超时。
分析可见,抢劫某个子树可能 被执行多次,
可以使用map记录抢劫某个子树的获取最大利益,下次只需要查表即可,
int dfs(TreeNode *root,unordered_map<TreeNode*,int> &table){ if(root!=NULL) { if(table.find(root)!=table.end()) return table[root]; int robed=root->val; if(root->left){ robed+=(dfs(root->left->left,table)+dfs(root->left->right,table)); } if(root->right){ robed+=(dfs(root->right->left,table)+dfs(root->right->right,table)); } int nonrobed=dfs(root->left,table)+dfs(root->right,table); table[root]= max(robed,nonrobed); return table[root]; } return 0; } int rob(TreeNode* root) { unordered_map<TreeNode*,int> table; return dfs(root,table); }
解法二:
递归函数返回一个大小为2的一维数组res,其中res[0]表示抢劫当前节点值的最大值,res[1]表示不抢劫当前节点的最大值,那么我们在遍历某个节点时,首先对其左右子节点调用递归函数,分别得到包含与不包含左子节点值的最大值,和包含于不包含右子节点值的最大值,那么当前节点的res[1]就是左子节点两种情况的较大值加上右子节点两种情况的较大值,res[0]就是不包含左子节点值的最大值加上不包含右子节点值的最大值,和当前节点值之和,返回即可
vector<int> dfs(TreeNode *root){ vector<int> res(2,0);//0 存储robed 最大利益, 1,nonrobed 最大利益 if(!root) return res; vector<int> lres=dfs(root->left); vector<int> rres=dfs(root->right); res[0]=lres[1]+rres[1]+root->val; res[1]=max(lres[0],lres[1])+max(rres[0],rres[1]); return res; } int rob(TreeNode* root) { vector<int> res=dfs(root); return max(res[0],res[1]); }
时间: 2024-10-03 21:41:32