( “树” 之 DFS) 337. 打家劫舍 III ——【Leetcode每日一题】
LeetCode 每日 DFS III 打家劫舍
2023-09-14 09:01:27 时间
337. 打家劫舍 III
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root
。
除了 root
之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root
。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
示例 1:
输入: root = [3,2,3,null,3,null,1]
输出: 7
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7
示例 2:
输入: root = [3,4,5,1,3,null,1]
输出: 9
解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9
提示:
- 树的节点数在 [ 1 , 1 0 4 ] [1, 10^4] [1,104] 范围内
- 0 < = N o d e . v a l < = 1 0 4 0 <= Node.val <= 10^4 0<=Node.val<=104
思路:DFS
分析:
每个节点都有偷或不偷两种可能,但是有一定的限制,如下:
- 若父节点不偷,子节点既能偷,也能不偷
- 若父节点偷,子节点只能不偷
解法:
由于每个节点都有两种可能,所以我们需要一个一维数组来保留这两种可能:
- 若当前节点不偷,其左孩子和有孩子既能偷,也能不偷, 取最大值,状态转移方程为:
r e s [ 0 ] = m a x ( l e f t [ 0 ] , l e f t [ 1 ] ) + M a t h . m a x ( r i g h t [ 0 ] , r i g h t [ 1 ] ) res[0] = max(left[0], left[1]) + Math.max(right[0], right[1]) res[0]=max(left[0],left[1])+Math.max(right[0],right[1]) - 若父节点偷,当前节点的金额加上子节点只能不偷时的金额,状态转移方程为:
r e s [ 1 ] = r o o t . v a l + l e f t [ 0 ] + r i g h t [ 0 ] res[1] = root.val + left[0] + right[0] res[1]=root.val+left[0]+right[0] - 递归即可求出小偷能够盗取的最高金额。
代码:(Java、C++)
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int rob(TreeNode root) {
//刚开始时,该节点既能偷,也能不偷, 取最大值
int[] res = takeOrNot(root);
return Math.max(res[0], res[1]);
}
public int[] takeOrNot (TreeNode root){
if(root == null) return new int[2];
int[] res = new int[2];
int[] left = takeOrNot(root.left);
int[] right = takeOrNot(root.right);
//如果没有偷当前节点,则其左孩子和有孩子既能偷,也能不偷, 取最大值
res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
//如果偷了当前节点,则其左孩子和有孩子都不能偷
res[1] = root.val + left[0] + right[0];
return res;
}
}
C++
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int rob(TreeNode* root) {
vector<int> res = takeOrNot(root);
return max(res[0], res[1]);
}
vector<int> takeOrNot (TreeNode* root){
if(root == NULL) return {0, 0};
vector<int> res = {0, 0};
vector<int> left = takeOrNot(root->left);
vector<int> right = takeOrNot(root->right);
//如果没有偷当前节点,则其左孩子和有孩子既能偷,也能不偷, 取最大值
res[0] = max(left[0], left[1]) +max(right[0], right[1]);
//如果偷了当前节点,则其左孩子和有孩子都不能偷
res[1] = root->val + left[0] + right[0];
return res;
}
};
运行结果:
复杂度分析:
- 时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
为树的结点数目。 - 空间复杂度: O ( n ) O(n) O(n)。递归栈最坏情况下需要 O ( n ) O(n) O(n)的空间。
题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我 leetCode专栏,每日更新!
注: 如有不足,欢迎指正!
相关文章
- Java实现 LeetCode 628 三个数的最大乘积(暴力大法)
- Java实现 LeetCode 391 完美矩形
- Java实现 LeetCode 374 猜数字大小
- Java实现 LeetCode 365 水壶问题
- Java实现 LeetCode 168 Excel表列名称
- Java实现 LeetCode 44 通配符匹配
- LeetCode(2):Add Two Numbers 两数相加
- 每日一道 LeetCode (52):三数之和
- 每日一道 LeetCode (36):相交链表
- 每日一道 LeetCode (22):二叉树的最大深度
- 每日一道 LeetCode (12):最大子序和
- 每日一道 LeetCode (7):合并两个有序链表
- 每日一道 LeetCode (3):回文数
- 每日一道 LeetCode (1):两数之和
- [LeetCode] Search a 2D Matrix
- ( “树” 之 DFS) 687. 最长同值路径 ——【Leetcode每日一题】
- ( “树” 之 DFS) 404. 左叶子之和 ——【Leetcode每日一题】
- ( “树” 之 DFS) 101. 对称二叉树 ——【Leetcode每日一题】
- (链表专题) 725. 分隔链表 ——【Leetcode每日一题】
- 628. 三个数的最大乘积 ——【Leetcode每日一题】
- 67. 二进制求和——【Leetcode每日一题】
- 172. 阶乘后的零——【Leetcode每日一题】
- 504. 七进制数——【Leetcode每日一题】
- 714. 买卖股票的最佳时机含手续费——【Leetcode每日一题】
- 518. 零钱兑换 II ——【Leetcode每日一题】
- C++ leetcode之排列与组合专题
- Python 刷Leetcode题库,顺带学英语单词(43)
- Leetcode 1576. 替换所有的问号(可以,一次过)
- LeetCode——Populating Next Right Pointers in Each Node II
- 【Leetcode刷题Python】16. 最接近的三数之和
- 【LeetCode】八皇后