题目
968. 监控二叉树
困难
相关标签
树 深度优先搜索 动态规划 二叉树
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
示例 1:
输入:[0,0,null,0,0] 输出:1 解释:如图所示,一台摄像头足以监控所有节点。
示例 2:
输入:[0,0,null,0,null,0,null,null,0] 输出:2 解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。
提示:
- 给定树的节点数的范围是
[1, 1000]
。 - 每个节点的值都是 0。
思路和解题方法
代码的目的是解决二叉树问题,具体来说是判断在二叉树中最少需要安装多少个监控摄像头才能覆盖所有节点。这里的监控摄像头可以覆盖其所在节点、其父节点以及其子节点。
该问题可以通过递归遍历二叉树的方式来解决。对于每个节点,有以下几种情况:
- 如果当前节点为空,返回2表示该节点不需要被监控。
if (cur == NULL) return 2;
- 如果左右子树都不需要被监控,则当前节点需要被监控,并且需要安装一个监控摄像头。
if (left == 2 && right == 2) return 0;
- 如果左右子树中有节点需要被监控,则当前节点不需要被监控。
if (left == 0 || right == 0) { ans++; return 1; }
- 如果左右子树中有节点已经被监控,则当前节点不需要被监控。
if (left == 1 || right == 1) return 2;
- 其他情况返回-1。
return -1;
在递归遍历完整棵树后,根据根节点的返回值来确定是否需要在根节点处安装监控摄像头。
if (traversal(root) == 0) { ans++; }
最终,函数返回需要安装的监控摄像头数量。
在这个代码中,变量
ans
记录需要安装的监控摄像头数量。函数traversal
返回值有以下几种情况:
- 返回2表示当前节点不需要被监控。
- 返回1表示当前节点已被监控。
- 返回0表示当前节点需要被监控。
通过递归遍历左右子树,可以得到左右子树的返回值,从而判断当前节点是否需要被监控。如果需要被监控,则在
ans
中增加1。
复杂度
时间复杂度:
O(N)
时间复杂度是O(N),其中N是二叉树中节点的数量。因为我们需要遍历每个节点一次来判断是否需要安装监控摄像头,所以时间复杂度与节点数量成正比。
空间复杂度
O(N)
空间复杂度是O(N),其中H是二叉树的高度。在递归过程中,系统会使用栈来保存每个递归调用的上下文信息。最坏情况下,二叉树是一个单链表,高度为N,此时递归调用的深度也是N,所以空间复杂度为O(N)。
c++ 代码
class Solution {
public:
int ans; // 记录需要安装的监控摄像头数量
int traversal(TreeNode* cur) {
if (cur == NULL) return 2; // 当前节点为空,返回2表示该节点不需要被监控
int left = traversal(cur->left); // 递归遍历左子树
int right = traversal(cur->right); // 递归遍历右子树
if (left == 2 && right == 2) return 0; // 左右子树都不需要被监控,则当前节点需要被监控
if (left == 0 || right == 0) { // 左右子树中有节点需要被监控
ans++; // 安装一个监控摄像头
return 1; // 返回1表示当前节点已被监控
}
if (left == 1 || right == 1) return 2; // 左右子树中有节点已被监控,则当前节点不需要被监控
return -1; // 若出现其他情况,返回-1
}
int minCameraCover(TreeNode* root) {
ans = 0;
if (traversal(root) == 0) {
ans++; // 根节点需要被监控,安装一个监控摄像头
}
return ans; // 返回需要安装的监控摄像头数量
}
};
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。