题目:
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 1Maximum amount of money the thief can rob = 3 + 3 + 1 = 7 .
Example 2:
3 / \ 4 5 / \ \ 1 3 1Maximum amount of money the thief can rob = 4 + 5 = 9 .
思路:
二叉树一般情况下用递归是最好的办法。分析本题目可知,要想获得最大值有两种选择:
1)抢劫根节点,那么此时就不能抢劫左右子树的根节点;
2)不抢劫根节点,那么此时就可以抢劫左右子树的根节点。
两种情况中取受益最大者即可。在实现中值得注意的是,在递归过程中有可能会引起重复计算。例如代码片段1中,我们在rob(root->left)的调用过程中会调用rob(root->left->left),而这个调用在rob(root)中也出现,导致大量重复计算。一种比较好的递归方式见代码片段2,我们采用“首递归”,并用传递引用的方式记录左右子树已经取得的最大值,可以完美地避免重复计算。(测试结果表明代码片段2的效率比代码片段1的效率高100倍左右)
代码:
1、低效递归:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int rob(TreeNode* root) {
if (!root) {
return 0;
}
int rob_root = root->val;
if (root->left) {
rob_root += rob(root->left->left);
rob_root += rob(root->left->right);
}
if (root->right) {
rob_root += rob(root->right->left);
rob_root += rob(root->right->right);
}
int not_rob_root = rob(root->left);
not_rob_root += rob(root->right);
return max(rob_root, not_rob_root);
}
};
2、高效递归:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int rob(TreeNode* root) {
int left = 0, right = 0;
return rob(root, left, right);
}
private:
int rob(TreeNode* root, int &left, int &right) {
if(!root) {
return 0;
}
int left_left = 0, left_right = 0, right_left = 0, right_right = 0;
left = rob(root->left, left_left, left_right); // left_left and left_right will be updated during recursions
right = rob(root->right, right_left, right_right); // right_left and right_right will be updated during recursions
return max(root->val + left_left + left_right + right_left + right_right, left + right);
}
};