打家劫舍III(力扣第337题)

题目:

  在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:

输入: [3,2,3,null,3,null,1]

     3
    / 
   2   3
        
     3   1

输出: 7 
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

示例2:

输入: [3,4,5,1,3,null,1]

     3
    / 
   4   5
  /     
 1   3   1

输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.

分析:

  透过现象看本质,其实就是邻近节点的值不能同时获取,求出所能获取的最大和。对于二叉树问题,一般从最简单的情况去分析,然后进行一系列的重复性递归操作即可解决。我们将二叉树分为三个部分,第一部分是父亲结点,第二部分是两个左右子结点,第三部分是两个左右子节点的所有子树。为什么要分成这几个部分呢?那是因为根据题意可知,父亲结点的值和其左右子结点的值是不可兼得的,左右子结点的值和它们各自的孩子结点的值是不可兼得的,但是左右子结点的父亲结点的值和左右子结点的孩子结点的值可以兼得,因为第一部分的父亲结点一定和其左右子结点的所有子树结点不直接相连所以无论第三部分的子树们如何选定具体的结点,只需保证第三部分都是基于它们那些子树情况下的最大和即可(这就涉及了递归),最终我们将第一部分和第三部分相加与第二部分的值进行比较,哪个大就返回哪个即可。

  其中第三部分是不一定存在的,如果第三部分不存在,那么就只用第一部分和第二部分进行比较。

代码:

public int rob(TreeNode root) {

        if (root == null){
            return 0;
        }
        getMaxMoney(root);
        return getMaxMoney(root);
    }

    private int getMaxMoney(TreeNode root){

        if (root == null){
            return 0;
        }

        if (root.left == null && root.right == null){
            return root.val;
        }
        int childMoney = getMaxMoney(root.left) + getMaxMoney(root.right);
        int fatherMoney = root.val;
        if (root.left != null){
            fatherMoney += getMaxMoney(root.left.left);
            fatherMoney += getMaxMoney(root.left.right);
        }

        if (root.right != null){
            fatherMoney += getMaxMoney(root.right.left);
            fatherMoney += getMaxMoney(root.right.right);
        }

        return Math.max(fatherMoney,childMoney);
    }
原文地址:https://www.cnblogs.com/yxym2016/p/13472858.html