【每日算法Day 106】打家劫舍系列最后一弹,撑住你就赢了!

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

题目链接


LeetCode 337. 打家劫舍 III[1]

往期回顾:打家劫舍 I :

【每日算法Day 104】偷电瓶的周某今天放出来了,还不赶紧做这道题防范一下![2]

往期回顾:打家劫舍 II :

【每日算法Day 105】打家劫舍第二弹:看好你的电瓶车![3]

题目描述


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

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

示例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.

题解


这次是在一棵树上偷窃了,做法还是一样。对于结点 r 来说,我们还是分为偷和不偷两种情况。

如果偷的话,它的左右儿子就不能偷了,所以最大价值就是左儿子不偷的最大价值,加上右儿子不偷的最大价值,再加上 r 的价值。

而如果不偷的话,最大价值就是左儿子偷或不偷的最大价值,加上右儿子偷或不偷的最大价值。

因为需要用到儿子结点偷和不偷两个价值,所以需要在 dfs 时返回两个值,用来表示偷和不偷两个最大价值,具体实现时用 pair 来表示。

可能有人会用另一种实现方式,用 dfs0 表示不偷的最大价值,dfs1 表示偷的最大价值,然后两个函数互相调用。注意这样理论上是可行的,但是会产生很多重复计算,最终会超时。所以这种方法需要记忆化搜索,比较麻烦,需要用 map 来保存每个结点的答案。

代码


复杂实现方式(c++)

classSolution {
public:    
unordered_map<TreeNode*, int>dp0, dp1;
intdfs0(TreeNode*root) {     
if (!root) return0;  
if (dp0.find(root) !=dp0.end()) returndp0[root];  
intres=0;    
res+=max(dfs0(root->left), dfs1(root->left));  
res+=max(dfs0(root->right), dfs1(root->right));    
returndp0[root]=res;  
    }
intdfs1(TreeNode*root) {    
if (!root) return0;    
if (dp1.find(root) !=dp1.end()) returndp1[root];  
intres=root->val;      
res+=dfs0(root->left);     
res+=dfs0(root->right);   
returndp1[root]=res;    
    }
introb(TreeNode*root) {  
if (!root) return0;    
dp0.clear();      
dp1.clear();    
returnmax(dfs0(root), dfs1(root));
    }
};

精简实现方式(c++)

classSolution {
public:   
typedefpair<int, int>pii;
piidfs(TreeNode*root) {   
if (!root) return {0, 0}; 
piil=dfs(root->left);    
piir=dfs(root->right);    
intr0=max(l.first, l.second) +max(r.first, r.second);
intr1=l.first+r.first+root->val;   
return {r0, r1}; 
    }
introb(TreeNode*root) {    
piires=dfs(root);     
returnmax(res.first, res.second);  
    }
};

参考资料


[1]

LeetCode 337. 打家劫舍 III: https://leetcode-cn.com/problems/house-robber-iii/

[2]

【每日算法Day 104】偷电瓶的周某今天放出来了,还不赶紧做这道题防范一下!: https://godweiyang.com/2020/04/18/leetcode-198/

[3]

【每日算法Day 105】打家劫舍第二弹:看好你的电瓶车!: https://godweiyang.com/2020/04/19/leetcode-213/

image.png

作者简介:godweiyang知乎同名华东师范大学计算机系硕士在读,方向自然语言处理与深度学习喜欢与人分享技术与知识,期待与你的进一步交流~


相关文章
|
3月前
leetcode-846:一手顺子
leetcode-846:一手顺子
12 0
|
4月前
|
Java
【LeetCode-六月每日一题-】-回文数
【LeetCode-六月每日一题-】-回文数
|
9月前
|
机器学习/深度学习
《蓝桥杯每日一题》背包dp·AcWing3382. 整数拆分
《蓝桥杯每日一题》背包dp·AcWing3382. 整数拆分
46 0
|
9月前
《蓝桥杯每日一题》递推·AcWing 3777. 砖块
《蓝桥杯每日一题》递推·AcWing 3777. 砖块
49 0
|
10月前
|
机器学习/深度学习 存储 算法
代码随想录训练营day48| 198.打家劫舍 213.打家劫舍II 337.打家劫舍III
代码随想录训练营day48| 198.打家劫舍 213.打家劫舍II 337.打家劫舍III
|
11月前
|
算法 C++
【每日算法Day 106】打家劫舍系列最后一弹,撑住你就赢了!
【每日算法Day 106】打家劫舍系列最后一弹,撑住你就赢了!
|
11月前
|
存储
AcWing第98和99周赛
AcWing第98和99周赛
76 0
|
机器学习/深度学习
【蓝桥杯集训·每日一题】 AcWing 3996. 涂色
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 区间DP Unique函数
88 0
|
机器学习/深度学习 编译器
【AcWing周赛】AcWing第85场周赛
目录 &lt;一&gt;Acwing 4791. 死或生 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 &lt;二&gt;Acwing 4792. 最大价值 一、题目 1、原题链接 2、题目描述 二、解题报告: 1、思路分析 2、时间复杂度 3、代码详解 &lt;三&gt;Acwing 4793. 危险程度 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 &lt;四&gt; 知识风暴 1、排序不等式 2、贪心法 3、数据范围 4、并查集 基本操作
63 0
|
机器学习/深度学习 人工智能 安全
【AcWing周赛】AcWing第86场周赛
目录 <一>AcWing 4794. 健身 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 <二>AcWing 4795. 安全区域 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 <三>AcWing 4796. 删除序列 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
59 0