Problem statement:
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.
Solution:
This is another question about house robbery. But it is totally different as the data structure changes from array to tree, but keeps the same rule that can not rob the directly connected nodes(parent and children relationship). It still follows dynamic programming philosophy to update the node value from the lower level to current node, and go up until the root.
The problem is how to get the depending values of DP?
It matches the DFS template with the return value. We traverse to the leaf(divide the big problem into small ones), process each node(DP processing), and go up until root(assemble the small problems into big). In order to update current node, we need the return value from it`s left and right tree. It also belongs to divide and conquer.
Return value type:
I used two different DP formula in 121. Best Time to Buy and Sell Stock.
Here, it is not applicable for dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]), it will be more complicated to store values from two levels.
For the return type of each node, it should include two values. I choose pair<int, int>.
- pair.first is the max value if we rob current house
- pair.second is the max value if we do not rob current house
DP processing:
We should get two values: pair.first and pair.second.
In order to update pair.first: the lower level houses must not be robbed, it is the sum of left and right.
pair.first = node->val + left.second + right.second;
For pair.second: left and right could both rob or do not rob. We just choose the max value from left and right.
pair.second = max(left.first,left.second) + max(right.first, right.second) ;
The code is as following, time complexity is O(n), n is the number of tree nodes.
/** * 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) { pair<int, int> root_val = rob_dfs(root); return max(root_val.first, root_val.second); } private: // pair.first: the value rob current house // pair.second: the value not rob current house pair<int, int> rob_dfs(TreeNode* root){ if(root == NULL){ return {0, 0}; } pair<int, int> left = rob_dfs(root->left); pair<int, int> right = rob_dfs(root->right); pair<int, int> cur_node; // if rob, pair.first is the sum of current node value and not rob of left and right cur_node.first = root->val + left.second + right.second; // if do not rob, pair.second is the sum of max of left and max of right cur_node.second = max(left.first, left.second) + max(right.first, right.second); return cur_node; } };