968. 监控二叉树

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

本题首先要注意到,叶子结点处不放摄像头,在叶子结点的父节点处放摄像头,所用摄像头最少
局部最优:让叶子节点的父节点安摄像头,所用摄像头最少
整体最优:全部摄像头数量所用最少!

首先确定遍历顺序,由于我们从叶子结点开始,所以使用后序遍历(左右中),注意向左孩子和右孩子遍历都用int接收返回值,用来推导中间节点的状态

int traversal(TreeNode* cur) {

    // 空节点,该节点有覆盖
    if (终止条件) return ;

    int left = traversal(cur->left);    // 左
    int right = traversal(cur->right);  // 右

    逻辑处理                            // 中
    return ;
}

接着处理中间节点的状态,根据左右孩子的返回值,由题可知,节点有三种状态,可用三个数字表示:
0:节点没有被摄像头覆盖 1:节点处有摄像头 2:节点处无摄像头但被覆盖
那么遇到空节点该如何判断覆盖情况?由于需要在叶子结点的父节点处放置摄像头,所以空节点处不能有摄像头,不然叶子结点就是有覆盖状态;空节点也不能是无覆盖状态,否则叶子结点处就需要放置摄像头,所以遇到空节点应返回2。

接下来讨论中间节点的情况:
(1)左右孩子都有覆盖,此时中间节点应该是无覆盖状态
(2)左右孩子有一个是无覆盖状态,此时中间节点应该放置摄像头
left == 0 && right == 0 左右节点无覆盖
left == 1 && right == 0 左节点有摄像头,右节点无覆盖
left == 0 && right == 1 左节点有无覆盖,右节点摄像头
left == 0 && right == 2 左节点无覆盖,右节点覆盖
left == 2 && right == 0 左节点覆盖,右节点无覆盖
(3)左右孩子有一个有摄像头,此时中间节点应该是有覆盖状态
left == 1 && right == 2 左节点有摄像头,右节点有覆盖
left == 2 && right == 1 左节点有覆盖,右节点有摄像头
left == 1 && right == 1 左右节点都有摄像头
(注意,左右孩子有一个有摄像头,另一个无覆盖的情况已经讨论过)
(4)头结点没有覆盖
递归结束后判断根节点状态,若无覆盖则摄像头数量加一

代码如下:

// 版本一
class Solution {
private:
    int result;
    int traversal(TreeNode* cur) {

        // 空节点,该节点有覆盖
        if (cur == NULL) return 2;

        int left = traversal(cur->left);    // 左
        int right = traversal(cur->right);  // 右

        // 情况1
        // 左右节点都有覆盖
        if (left == 2 && right == 2) return 0;

        // 情况2
        // 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;
        }

        // 情况3
        // left == 1 && right == 2 左节点有摄像头,右节点有覆盖
        // left == 2 && right == 1 左节点有覆盖,右节点有摄像头
        // left == 1 && right == 1 左右节点都有摄像头
        // 其他情况前段代码均已覆盖
        if (left == 1 || right == 1) return 2;

        // 以上代码我没有使用else,主要是为了把各个分支条件展现出来,这样代码有助于读者理解
        // 这个 return -1 逻辑不会走到这里。
        return -1;
    }

public:
    int minCameraCover(TreeNode* root) {
        result = 0;
        // 情况4
        if (traversal(root) == 0) { // root 无覆盖
            result++;
        }
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值