题目

给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。

计算监控树的所有节点所需的最小摄像头数量。

示例 1:

img

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

示例 2:

img

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

提示:

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

解答

  • 贪心算法

本题是一道贪心算法的题目。通过对题目进行分析,我们可以发现有以下几种情况:

1.如果一个节点没有被监控,那么它必须要安装一个摄像头。

2.如果一个节点安装了摄像头,那么它的父节点就可以被监控了。

3.如果一个节点的子节点被监控了,那么这个节点也可以被监控。

因此,我们可以采用自下而上的方式进行处理,从叶子节点开始向根节点进行处理。对于每个节点,我们可以有三种状态:

0:该节点没有装摄像头,且它的子节点中也没有装摄像头的节点,此时应该给他装一个摄像头。

1:该节点没有装摄像头,但是它的子节点中至少有一个装摄像头的节点,此时应该给他的父节点装一个摄像头。

2:该节点装摄像头了,因此它无需再安装一个摄像头。

对于每个节点,我们可以采用递归的方式进行处理。当节点为叶子节点时,它的状态为0。对于其他节点,如果它的子节点中存在状态为0的节点,那么该节点的状态为1,表示需要安装摄像头。如果它的子节点中都存在状态为1或2的节点,那么该节点的状态为0,表示不需要安装摄像头,但是它的父节点需要安装摄像头。如果它的子节点中存在状态为2的节点,那么该节点的状态为1,表示不需要安装摄像头,因为它的子节点已经可以覆盖它了。

最后,根据根节点的状态来判断是否需要安装摄像头。如果根节点的状态为0或1,那么需要安装一个摄像头。如果根节点的状态为2,那么不需要安装摄像头。

/**
 * 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 minCameraCover(TreeNode* root) {
        int res = 0;
        if (dfs(root, res) == 0) { // 根节点未被监控
            res++;
        }
        return res;
    }

    int dfs(TreeNode* node, int& res) {
        if (node == nullptr) {
            return 2; // 空节点不需要监控,返回2
        }
        int left = dfs(node->left, res);
        int right = dfs(node->right, res);
        if (left == 0 || right == 0) { // 左右子节点有未被监控的节点,该节点需要安装摄像头
            res++; // 安装了摄像头
            return 1; // return 1是指该节点没有被监控,但是它的子节点中至少有一个被监控的节点。
        } else if (left == 1 || right == 1) { // 左右子节点中至少有一个节点被监控
            return 2; // return 2是指该节点被监控了。
        } else { // 左右子节点均被监控
            return 0; // return 0是指该节点没有装摄像头
        }
    }
};

其中,dfs函数的返回值为当前节点的状态。如果返回值为0,表示当前节点需要安装摄像头;如果返回值为1,表示当前节点不需要安装摄像头,但是它的父节点需要安装摄像头;如果返回值为2,表示当前节点不需要安装摄像头。res为引用类型,表示安装摄像头的数量。