Problem
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
Examlpe 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.
Algorithm
整理一下题意:某小偷要在二叉树里面偷东西。二叉树每个节点表示一户人家,每个节点的值代表小偷能偷走的价值。小偷从根节点出发偷东西,要求不能连续偷相邻两个节点的值。问小偷能偷走的最大价值和是多少?
小偷问题的进化版,由一维数组到二维数组到现在的二叉树。由于之前做了一题是动态规划解题版本的,所以自然先想到这个思路。写成递归版本代码如下。
//类动规版本,Time Limit Exceeded
class Solution {
public:
int rob(TreeNode* root) {
if (root==NULL) return 0;
int val = 0;
if (root->left) {
val += rob(root->left->left) + rob(root->left->right);
}
if (root->right) {
val += rob(root->right->left) + rob(root->right->right);
}
return max(val + root->val, rob(root->left) + rob(root->right));
}
};
完成题目后提交,未通过,显示Time Limit Exceeded,超时。果然直接递归会超时…
于是考虑新的方法。每个节点考虑选或不选两个状态。若选择了该节点,则子节点只能取不可选状态的结果。若未选择该节点,则子节点可选可不选,取二者较大的结果。
基于这个思路,可以设一个int向量result,result[0]表示当前节点选中的最大值,result[1]表示当前节点不选的最大值。在DFS函数中,由同样思路,用int向量res表示两种状态的结果,则有
不选节点:res[0]=max(l[0],l[1])+max(r[0],r[1]);
选节点:res[1]=l[0]+r[0]+p->val;
代码如下。
//DFS
class Solution {
public:
int rob(TreeNode* root) {
vector<int> result=dfs(root);
return max(result[0],result[1]);
}
vector<int> dfs(TreeNode*p){
if(p==NULL) return vector<int>(2,0);
vector<int> l=dfs(p->left);
vector<int> r=dfs(p->right);
vector<int> res(2,0);
res[0]=max(l[0],l[1])+max(r[0],r[1]);
res[1]=l[0]+r[0]+p->val;
return res;
}
};