小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root
。除了 root
之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。给定二叉树的 root
。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
>>思路和分析
>>递归三部曲 + 动规五部曲
1.确定递归函数的 参数 和 返回值
返回值是一个长度为2的dp数组,用来记录节点 “偷” 与 “不偷” 得到的金钱
- vector<int> robTree(TreeNode* cur) {
- ...
- }
常见疑惑(O_O)?长度为2的dp数组怎么标记树中的每个节点的状态呢?
【解惑】其实在递归的过程中,系统栈会保存每一层递归的参数~
2.确定终止条件
在遍历过程中,若是遇到空节点,无论 “偷” 还是 “不偷” 都是 0 ,所以直接返回 {0,0}。因为空节点的金钱收益为0。而这也相当于 dp 数组的初始化
if(cur == NULL) return vector<int>{0,0};
3.确定遍历顺序
4.确定单层递归的逻辑
5.举例推导 dp 数组
最后max{result[0],result[1]}; 的返回值就是头结点偷得的最大金钱
- class Solution {
- public:
- // 长度为2的数组,0:不偷,1:偷
- vector<int> robTree(TreeNode* cur) {
- if(cur == NULL) return vector<int>{0,0};
- vector<int> left = robTree(cur->left);
- vector<int> right = robTree(cur->right);
- // 偷 cur,那么就不能偷左右节点
- int val1 = cur->val + left[0] + right[0];
- // 不偷 cur,那么可以偷也可以不偷左右节点,则取较大的情况
- int val2 = max(left[0],left[1]) + max(right[0],right[1]);
- // cout << "{val2 , val1} :" << val2 << "," << val1 <
- return {val2,val1};
- }
-
- int rob(TreeNode* root) {
- vector<int> result = robTree(root);
- return max(result[0],result[1]);
- }
- };
参考和推荐文章、视频
动态规划,房间连成树了,偷不偷呢?| LeetCode:337.打家劫舍3_哔哩哔哩_bilibili
来自代码随想录的课堂截图: