// Source : https://leetcode.com/problems/house-robber-iii/ // Author : Calinescu Valentin, Hao Chen // Date : 2016-04-29 /*************************************************************************************** * * 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. * Credits: * Special thanks to @dietpepsi for adding this problem and creating all test cases. * ***************************************************************************************/ /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ /* * Solution 1 - O(N log N) * ========= * * We can use a recursive function that computes the solution for every node of the tree * using the previous solutions calculated for the left and right subtrees. At every step * we have 2 options: * * 1) Take the value of the current node + the solution of the left and right subtrees of * each of the left and right children of the current node. * 2) Take the solution of the left and right subtrees of the current node, skipping over * its value. * * This way we can make sure that we do not pick 2 adjacent nodes. * * If we implemented this right away we would get TLE. Thus, we need to optimize the * algorithm. One key observation would be that we only need to compute the solution for * a certain node once. We can use memoization to calculate every value once and then * retrieve it when we get subsequent calls. As the header of the recursive function * doesn't allow additional parameters we can use a map to link every node(a pointer) to * its solution(an int). For every call the map lookup of an element and its insertion * take logarithmic time and there are a constant number of calls for each node. Thus, the * algorithm takes O(N log N) time to finish. * */ class Solution { public: map<TreeNode*, int> dict; int rob(TreeNode* root) { if(root == NULL) return 0; else if(dict.find(root) == dict.end()) { int lwith = rob(root->left); int rwith = rob(root->right); int lwithout = 0, rwithout = 0; if(root->left != NULL) lwithout = rob(root->left->left) + rob(root->left->right); if(root->right != NULL) rwithout = rob(root->right->left) + rob(root->right->right); //cout << lwith << " " << rwith << " " << lwithout << " " << rwithout << '\n'; dict[root] = max(root->val + lwithout + rwithout, lwith + rwith); } return dict[root]; } }; // Another implementation - Hao Chen class Solution { public: int max(int a, int b) { return a > b ? a: b; } int max(int a, int b, int c) { return max(a, max(b,c)); } int max(int a, int b, int c, int d) { return max(a, max(b, max(c,d))); } void rob_or_not(TreeNode* root, int& max_robbed, int& max_not_robbed) { // NULL room return 0; if (root == NULL) { max_robbed = max_not_robbed = 0; return ; } // we have two options, rob current room or not. int max_left_robbed, max_left_not_robbed; int max_right_robbed, max_right_not_robbed; rob_or_not(root->left, max_left_robbed, max_left_not_robbed); rob_or_not(root->right, max_right_robbed, max_right_not_robbed); // If root is robbed, then both left and right must not be robbed. max_robbed = root->val + max_left_not_robbed + max_right_not_robbed; // If root is not robbed, then 4 combinations are possible: // left is robbed or not and right is either robbed or not robbed, max_not_robbed = max(max_left_robbed + max_right_robbed, max_left_robbed + max_right_not_robbed, max_left_not_robbed + max_right_robbed, max_left_not_robbed + max_right_not_robbed); } int rob(TreeNode* root) { int robbed, not_robbed; rob_or_not(root, robbed, not_robbed); return max(robbed, not_robbed); } };