监控二叉树
题目链接:力扣题目链接
难度:困难
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
示例 :
输入:[0,0,null,0,0]
输出:1
解释:如图所示,一台摄像头足以监控所有节点。
思路
二叉树节点定义
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;
}
}
思路
从题目示例可以看出,所有的摄像头都没有放在叶子节点,摄像头可以覆盖上下中三层,如果放在叶子节点,就浪费了一层的覆盖,所以把摄像头放在叶子节点的父节点位置,才能充分利用摄像头的覆盖面积。要从下往上看,让叶子节点的父节点安装摄像头,所用摄像头最少。在二叉树中从低向上导,可以使用后序遍历也就是左右中的顺序,这样就可以在回溯的过程中从下到上进行推导了。
每个节点都有三种状态,情况一,该节点无覆盖,情况二,该节点有摄像头,情况三,该节点有覆盖。可以分别用三个数字表示三种情况的状态,0表示该节点无覆盖,1表示该节点有摄像头,2表示该节点有覆盖。空节点是有覆盖的,所以递归遇见了空节点,应该返回2。
贪心法
class Solution{
private int result = 0;
public int minCameraCover(TreeNode root) {
// root 无覆盖
if(travl(root) == 0) result++;
return result;
}
private int travl(TreeNode root){
// 空节点,该节点有覆盖
if(root == null) return 2;
int left = travl(root.left); // 左
int right = travl(root.right); // 右
// left == 0 && right == 0 左右节无覆盖
// left == 1 && right == 0 左节点有摄像头,右节点无覆盖
// left == 0 && right == 1 左节点无覆盖,右节点摄像头
// left == 0 && right == 2 左节点无覆盖,右节点覆盖
// left == 2 && right == 0 左节点覆盖,右节点无覆盖
if(left == 0 || right == 0){
result++;
return 1;
}
// 左右节点都有覆盖
if(left == 2 && right == 2){
return 0;
}
// left == 1 && right == 2 左节点有摄像头,右节点有覆盖
// left == 2 && right == 1 左节点有覆盖,右节点有摄像头
// left == 1 && right == 1 左右节点都有摄像头
// 其他情况前段代码均已覆盖
if(left == 1 || right == 1){
return 2;
}
return -1;
}
}