小偷又发现一个新的可行窃的地点。 这个地区只有一个入口,称为“根”。 除了根部之外,每栋房子有且只有一个父房子。 一番侦察之后,聪明的小偷意识到“这个地方的所有房屋形成了一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

在不触动警报的情况下,计算小偷一晚能盗取的最高金额。

示例 1:

     3
    / \
   2   3
    \   \ 
     3   1

能盗取的最高金额 = 3 + 3 + 1 = 7.

示例 2:

     3
    / \
   4   5
  / \   \ 
 1   3   1

能盗取的最高金额 = 4 + 5 = 9.

思路:这次是在树形结构中找不能相邻的最大金额数。首先我们可以这样想,对于每个节点,我们都可以进行选与不选两种方案,如果选,那么意味着它的左右节点不能被选,如果不选,也不是意味着我必须要选它的左右节点,还要接着判断左右节点是选还是不选。

class Solution {
public:
    int rootexclude(TreeNode* root)
    {
        if(root==NULL) return 0;
        return rob(root->left)+rob(root->right);
    }
    int rootinclude(TreeNode* root)
    {
        if(root==NULL) return 0;
        return rootexclude(root->left)+rootexclude(root->right)+root->val;
    }
    int rob(TreeNode* root) 
    {
        if(root==NULL) return 0;
        return max(rootinclude(root),rootexclude(root));
    }  
};

上述程序完美的体现了这个思想,其中rootinclude函数表示了将根节点选入,rootexclude函数表示不选根节点。我们最后回溯,只需要搞清楚对于整个二叉树的根节点来说,我是选还是不选,就可以得到最后的结果。

当然了,上述算法的时间复杂度并不低,因为三个函数互相调用递归的成本太大,有大神提出了动态规划的解法。

class Solution {
        int walk(TreeNode* root,int&val)
        {
            val=0;
            if(root==NULL)
                return 0;
            int left,right;
            val=walk(root->left,left)+walk(root->right,right);
            return max(val,left+right+root->val);   
      }
public:
    int rob(TreeNode* root) {
        int val;
        return walk(root,val);//这里采用引用传参的方式记录决策路径
    }
};

 

posted on 2018-08-01 17:47  Mini_Coconut  阅读(166)  评论(0编辑  收藏  举报