题目描述
【打家劫舍I】
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/house-robber-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
这个小偷这么聪明为啥还要偷东西
暴力解:最直观的思路
递归地定义一个函数,叫 “偷” ,即返回在给定节点为根的树中,偷得的最大价值,下面的“偷”都是指调用这个函数
- 如果当前节点root只有左孩子,那么有两种偷法:
1.偷root,+ 偷root左孩子的两个孩子
2.偷root的左孩子
返回大的结果作为偷root最大收益
- 只有右孩子同上操作
- 如果同时具有左右孩子,那么还是两种偷法
1.偷root和左右孩子的所有孩子
2.偷root的左右孩子
返回最大的值作为答案
注意边界条件是空节点,偷的价值为0,直接return 0
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int rob(TreeNode* root)
{
if(!root) return 0;
if(!root->left && !root->right) return root->val;
if(root->left && !root->right)
return max(root->val+rob(root->left->left)+rob(root->left->right), rob(root->left));
if(!root->left && root->right)
return max(root->val+rob(root->right->left)+rob(root->right->right), rob(root->right));
return max(root->val
+rob(root->left->left)+rob(root->left->right)
+rob(root->right->left)+rob(root->right->right)
, rob(root->left)+rob(root->right));
}
};
动态规划
由上面的暴力递归不难看出状态转移,那么就好用dp了
递归是自顶向下的,而动态规划是满足自底向上,即先求解子问题
对树后序遍历可以完美地满足:先解子问题,在解问题的要求,可以直接把问题的解保存在树的值里面,使用常数的额外空间
递归地定义函数 lrd(root) ,将以root为根的树的偷得的最大价值保存在root节点的val中
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
// 查询节点值,遇到空返回0,方便处理递归边界
int v(TreeNode*& root)
{
if(!root) return 0;
return root->val;
}
void lrd(TreeNode*& root)
{
if(!root) return;
// 先求解子问题
lrd(root->left);
lrd(root->right);
// 状态转移
if(root->left && !root->right)
root->val = max(root->val+v(root->left->left)+v(root->left->right), root->left->val);
else if(!root->left && root->right)
root->val = max(root->val+v(root->right->left)+v(root->right->right),root->right->val);
else if(root->left && root->right)
root->val = max(root->val+v(root->left->left)+v(root->left->right)+v(root->right->left)+v(root->right->right), root->left->val+root->right->val);
}
int rob(TreeNode* root)
{
if(!root) return 0;
lrd(root);
return root->val;
}
};