import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* 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.
* <p>
* Determine the maximum amount of money the thief can rob tonight without alerting the police.
* <p>
* 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.
* <p>
* Tags: Tree, Depth-first Search
* Similar Problems: (E) House Robber, (M) House Robber II
*/
public class HouseRobber3 {
private HouseRobber3 h;
/**
* If current house is robbed, then subtrees' roots cannot be robbed.
* The maximum is
* root.val + rob(root.left.left) + rob(root.left.right) + rob(root.right.left) + rob(root.right.right)
* If current house is robbed, then subtrees' roots can be robbed.
* The maximum is
* rob(root.left) + rob(root.right)
* The base case is where we don't need to calculate sub problems.
* When root is null in our case. Just return 0.
*/
public int rob(TreeNode root) {
int[] res = dfs(root);
return Math.max(res[0], res[1]);
}
/**
* @return An array of two integers, the first one is maximum with current node; the second is without current node.
*/
private int[] dfs(TreeNode node) {
if (node == null) return new int[2]; // Base case
int[] res = new int[2];
int[] left = dfs(node.left);
int[] right = dfs(node.right);
res[0] = node.val + left[1] + right[1];
res[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return res;
}
@Before
public void setUp() {
h = new HouseRobber3();
}
@Test
public void testExamples() {
TreeNode root = new TreeNode(3);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.right = new TreeNode(3);
root.right.right = new TreeNode(1);
Assert.assertEquals(7, h.rob(root));
root = new TreeNode(3);
root.left = new TreeNode(4);
root.right = new TreeNode(5);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(3);
root.right.right = new TreeNode(1);
Assert.assertEquals(9, h.rob(root));
root = new TreeNode(4);
root.left = new TreeNode(1);
root.left.left = new TreeNode(2);
root.left.left.left = new TreeNode(3);
Assert.assertEquals(7, h.rob(root));
}
@After
public void tearDown() {
h = null;
}
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
}