968. 监控二叉树
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
示例 1:
输入: [0,0,null,0,0]
输出: 1
解释: 如图所示,一台摄像头足以监控所有节点。
示例 2:
输入:[0,0,null,0,null,0,null,null,0]
输出:2
解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。
提示:
- 给定树的节点数的范围是
[1, 1000]。 - 每个节点的值都是 0。
贪心+递归+状态转移
思路
要在树中安装摄像头来监控到所有的树
遍历整棵树我们可以有两种方式,从上到下,或者从下到上
那么我们肯定希望每一个摄像头都能监控到更多的节点
遍历方式
- 从上到下遍历,那么可能最后一层的爷爷节点都安装了摄像头的话,叶子节点就都需要安装摄像头,肯定不是最少的摄像头
所以我们要从下到上遍历
- 让每个叶子节点的父节点安装摄像头,就能保证每颗摄像头都能覆盖尽量多的节点,从而使监视整棵树的节点数量最少
找到所有节点状态
每个节点的所有状态:
- 当前节点没有被覆盖,用0表示
- 当前节点有摄像头,用1表示
- 当前节点被覆盖,用2表示
- 当前节点没有摄像头(没有摄像头就是被覆盖,或者未被覆盖,上面三种状态已经包含了该状态)
当然我们还会遇到空节点null,比如叶子节点(子树都为null)的子节点为两个null
那么这个null节点的状态是什么呢:
- null没有被覆盖:那么我们就需要给null节点的父节点安装摄像头,这样就相当于给叶子节点安装摄像头,很明显不符合题意,数量肯定不是最少的
- null节点有摄像头:不符合题意,不能给null安装摄像头
- null节点被覆盖:那么null的父节点(叶子节点)就是未覆盖的状态,这时候我们就可以给null的爷爷节点(叶子节点的父节点)安装摄像头,满足我们的要求
如果某非叶子节点的子树为null:
- null没有被覆盖:那么单边的树上没一个节点都需要安装摄像头来覆盖null,很明显不正确
- null安装摄像头:不符合题意
- null节点被覆盖:此时不用考虑该null节点,只需要再覆盖其父节点即可
所以null节点的状态只能是被覆盖
并且找到状态转移方程
- 情况1: 左右子树至少有一个未覆盖0 left=0 right = 0
left=0 right = 1
left=0 right = 2
left=1 right = 0
left=2 right = 0
此时当前节点必然为未覆盖状态1
if(left === noCover||right===noCover){
res++
return isCamera
}
- 情况2:左右子树至少有一个安装摄像头
left=1 right=0
left=1 right=1
left=1 right=2
left=0 right=1
left=2 right=1
那么当前节点必然为已覆盖状态2
if(left === isCamera || right === isCamera){
return isCover
}
- 情况3:左右子树都被覆盖 left=1 right=1
if(left === isCover && right === isCover){
return noCover
}
那么当前节点就是无覆盖0
以上就是所有的情况了,每个节点3中状态,两个节点共9种状态,也可以跟据当前节点的3中状态,去反推出所有子节点的状态,道理是一样的
至此,我们已经找到三种状态方程
注意: 如果我们根节点的状态为未覆盖0,我们还需要在根节点安装一个摄像头
if(traversal(root)===noCover) res++
var minCameraCover = function (root) {
var noCover = 0
var isCover = 1
var isCamera = 2
var res = 0
var traversal = function(root){
if(root===null) return isCover
var left = traversal(root.left)
var right = traversal(root.right)
if(left === noCover||right===noCover){
res++
return isCamera
}
if(left === isCamera || right === isCamera){
return isCover
}
if(left === isCover && right === isCover){
return noCover
}
}
if(traversal(root)===noCover) res++
return res
};