Skip to content
本页目录

0968-监控二叉树

https://leetcode.cn/problems/binary-tree-cameras

给定一个二叉树,我们在树的节点上安装摄像头。 节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。 计算监控树的所有节点所需的最小摄像头数量。

示例 1:

输入:[0,0,null,0,0]
输出:1
解释:如图所示,一台摄像头足以监控所有节点。

示例 2:

输入:[0,0,null,0,null,0,null,null,0]
输出:2
解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。

提示:

给定树的节点数的范围是[1, 1000]。
每个节点的值都是 0。

思路【官方:树形dp】

https://leetcode.cn/problems/binary-tree-cameras/solution/jian-kong-er-cha-shu-by-leetcode-solution/

  • 以节点 root 为例,包含三种状态 (这三种状态很难想到)

  • 状态0 : root 处必须放置摄像头,所需要的最大摄像头数

  • 状态1 : 不管 root 处有没有放置摄像头,所需要的最大摄像头数

  • 状态2 : 覆盖左右两棵子树,所需要的最大的摄像头数

  • 状态0 = L2 + R2 + 1

  • 状态1 = min(状态0, min(L0+R2,L2+R0)) 即root自己放,或者左右子树放一个覆盖root

参考代码

csharp
public class Solution {
	
	private int[] dfs(TreeNode root){
		if(root == null){
			return new int[]{int.MaxValue / 2, 0, 0};
		}
		int[] left = dfs(root.left);
		int[] right = dfs(root.right);
		int[] arr = new int[3];
		arr[0] = left[2] + right[2] + 1;
		arr[1] = Math.Min(arr[0],Math.Min(left[0] + right[1], left[1] + right[0]));
		arr[2] = Math.Min(arr[0],left[1]+right[1]);
		return arr;
	}

    public int MinCameraCover(TreeNode root) {
    	int[] arr = dfs(root);
    	return arr[1];
    }
}

思路2【贪心算法】 思路真棒

https://leetcode.cn/problems/binary-tree-cameras/solution/968-jian-kong-er-cha-shu-di-gui-shang-de-zhuang-ta/

节点的3种状态

  • 0 : 该节点无覆盖
  • 1 : 该节点有摄像头
  • 2 : 该节点有覆盖 如果该节点没有摄像头,那么他属于 0 或者 2 的一种

贪心算法,就是尽量安装子节点的父亲(当子节点的子节点为空的时候) 空节点的状态应该属于 2,因为他不能装摄像头,但是也不用覆盖他,摄像头撞到空节点的爷爷即可

参考代码

csharp
public class Solution {

	private int result = 0;

	private int dfs(TreeNode root){
		if(root == null){
			return 2;
		}
		int left = dfs(root.left);
		int right = dfs(root.right);
		//根据左右状态推断当前摄像头状态,如果必须安装,则 result + 1

		if(left == 0 || right == 0){
			result++;
			return 1;
		}

		if(left == 1 || right == 1){
			return 2;
		}

		if(left == 2 && right == 2){
			return 0;
		}

		return -1;
	}

	public int MinCameraCover(TreeNode root) {
		if(dfs(root) == 0){
			result++;
		}
    	return result;
    }
}

参考代码:默写 2022-03-22

csharp
public class Solution {
    //贪心算法:最子节点不要安装,尽量安装他的父亲,然后爷爷那里也不用安装
    //定义三种状态: 很重要
    // 1. 该节点有摄像头
    // 2. 该节点有覆盖 (就是会被灯照到)
    // 0. 该节点无覆盖 (就是灯照不到)
    // 没有安装等 就属于(0,2)的一种情况
    // 特殊情况节点为 null 应该是属于2.有覆盖,因为只要他的爷爷装了摄像头,就算是覆盖成功的。
    // 通过 dfs 来计算节点是否需要安装摄像头
    int result = 0;
    private int dfs(TreeNode root){
        if(root == null){
            return 2;
        }
        int left = dfs(root.left);
        int right = dfs(root.right);
        if(left == 0 || right == 0){ //如果任何一个子节点没有被覆盖,自己必须安装摄像头
            result++;
            return 1;
        }
        else if(left == 1 || right == 1){ //如果任何一个子节点安装了摄像头,说明自己被覆盖了
            return 2;
        }
        //剩下的情况说明都是两个节点都是2,被其他节点覆盖了,所以当前节点无覆盖
        return 0;
    }

    public int MinCameraCover(TreeNode root) {
        if(dfs(root) == 0){
            result++;
        }
        return result;
    }
}

Released under the MIT License.