[leetcode]337. House Robber III

分手后的思念是犯贱 2022-08-22 00:01 205阅读 0赞

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:

  1. 3
  2. / \
  3. 2 3
  4. \ \
  5. 3 1

Maximum amount of money the thief can rob = 3 + 3 + 1 = 7 .

Example 2:

  1. 3
  2. / \
  3. 4 5
  4. / \ \
  5. 1 3 1

Maximum amount of money the thief can rob = 4 + 5 = 9.

算法分析

依然是这个场景,只不过“所有的房屋形成了一个二叉树结构”。首先我们可以明确的是,对于一棵给定的二叉树,每个结点可以对应一棵子树,而每棵子树的最大可偷盗金额(暂且称之为rob值)是确定的,我们需要求的是根结点的rob值。我依然尝试用递归的思想:可不可以先计算出根结点的左儿子和右儿子的rob值,然后得到根结点的rob值?答案是肯定的。不过,我们只从左右儿子的rob值和结点本身的val值还不足以推出该结点的rob值。因为倘若

1)左儿子和右儿子取得最大rob值时,左儿子和右儿子都没有被选中,则该结点的rob值可以等于左右儿子的rob值和结点本身的val值之和;

2)左儿子和右儿子取得最大rob值时,左儿子和右儿子都被选中,情况就变得很复杂。

进一步思考,我们可以记录下每个结点的include值和exclude值,其中,include值是包括该结点在内的最大可偷盗金额,exclude值是不包括该结点的最大可偷盗金额。每个结点的include值和exclude值完全可以通过其左右儿子的include值和exclude值得到。推导规则如下:

root.include = root.val + left.exclude + right.exclude

root.exclude = max(left.include,left.exclude) + max(right.include,right.exclude)

其中,root表示原结点,left表示其左儿子,right表示其右儿子。max是取两个数较大的那个。

数据结构分析

由于题目帮我们建好的类中没有exclude和include两个属性,于是我们自己新建一个类将这两个属性加进去。然后遍历二叉树的同时把我们需要的树(带有exclude和include属性值的数)建好。

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. public class Solution {
  11. public class MyNode {
  12. int val;
  13. int exclude;
  14. int include;
  15. MyNode left;
  16. MyNode right;
  17. }
  18. public int rob(TreeNode root) {
  19. if(root == null){
  20. return 0;
  21. }
  22. MyNode my = genMyNode(root);
  23. calRob(my);
  24. return my.exclude > my.include ? my.exclude : my.include;
  25. }
  26. /**
  27. * 生成带有include和exclude属性的二叉树
  28. */
  29. private MyNode genMyNode(TreeNode root){
  30. MyNode my = new MyNode();
  31. my.val = root.val;
  32. if(root.left != null){
  33. my.left = genMyNode(root.left);
  34. }
  35. else{
  36. my.left = null;
  37. }
  38. if(root.right != null){
  39. my.right = genMyNode(root.right);
  40. }
  41. else{
  42. my.right = null;
  43. }
  44. return my;
  45. }
  46. /**
  47. * 计算include值和exclude值
  48. */
  49. private void calRob(MyNode root){
  50. if(root.left == null && root.right == null){
  51. root.include = root.val;
  52. root.exclude = 0;
  53. }
  54. else if(root.left == null && root.right != null){
  55. calRob(root.right);
  56. root.include = root.val + root.right.exclude;
  57. root.exclude = root.right.exclude > root.right.include ? root.right.exclude : root.right.include;
  58. }
  59. else if(root.left != null && root.right == null){
  60. calRob(root.left);
  61. root.include = root.val + root.left.exclude;
  62. root.exclude = root.left.exclude > root.left.include ? root.left.exclude : root.left.include;
  63. }
  64. else{
  65. calRob(root.left);
  66. calRob(root.right);
  67. root.include = root.val + root.left.exclude + root.right.exclude;
  68. root.exclude = (root.left.exclude > root.left.include ? root.left.exclude : root.left.include) + (root.right.exclude > root.right.include ? root.right.exclude : root.right.include);
  69. }
  70. }
  71. }

发表评论

表情:
评论列表 (有 0 条评论,205人围观)

还没有评论,来说两句吧...

相关阅读