小偷又发现一个新的可行窃的地点。 这个地区只有一个入口,称为“根”。 除了根部之外,每栋房子有且只有一个父房子。 一番侦察之后,聪明的小偷意识到“这个地方的所有房屋形成了一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
在不触动警报的情况下,计算小偷一晚能盗取的最高金额。
示例 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);//这里采用引用传参的方式记录决策路径 } };