leetcode 968. 监控二叉树

最小支配集
从图G=(V,E)中,从点集V中选取一个子集P,使得图中其他任意一个节点可以与P中的点相连

照相机的集合可以看成集合P

每一个节点:
有两个变量需要考虑
是否放置了照相机
是否被监控

解法1:

从上至下求解 对于每一个子树 根节电的情况是已知的
1.放置了照相机被监控
2.没有放置照相机,被监控
3.没有放置照相机,并且没有被监控
isPlaced 表示是否放置了照相机
isCoverd 表示该节点是否被覆盖

class Solution {
public:
    int minCameraCover(TreeNode* root) {
        return min(findans(root,1,1),findans(root,0,0));
    }

    int findans(TreeNode* root,bool isPlaced,bool isCoverd){
        
        if(root==nullptr){
            return 0;
        }
        else{// have two children
            if(isPlaced){
                int ret = INT_MAX;
                int lp = findans(root->left,1,1);
                int lnp = findans(root->left,0,1);
                int rp = findans(root->right,1,1);
                int rnp = findans(root->right,0,1);
                ret = min(ret,lnp + rnp);
                ret = min(ret,lp + rp);
                ret = min(ret,lnp + rp);
                ret = min(ret,lp + rnp);
                return ret+1;
            }else{
                int ret = INT_MAX;
                if(isCoverd){

                    if(root->left==nullptr && root->right==nullptr){
                        return 0;
                    }else if(root->left!=nullptr && root->right!=nullptr){
                        int lp = findans(root->left,1,1);
                        int lnp = findans(root->left,0,0);
                        int rp = findans(root->right,1,1);
                        int rnp = findans(root->right,0,0);
                        ret = min(ret,lp + rp);
                        ret = min(ret,lnp + rp);
                        ret = min(ret,lp + rnp);
                        ret = min(ret,lnp + rnp);

                    }else if(root->left!=nullptr){
                        ret = min(ret,findans(root->left,1,1));
                        ret = min(ret,findans(root->left,0,0));
                    }else if(root->right!=nullptr){
                        ret = min(ret,findans(root->right,1,1) );
                        ret = min(ret,findans(root->right,0,0) );
                    }

                }else{
                    if(root->left==nullptr && root->right==nullptr){
                        return 1;
                    }else if(root->left!=nullptr && root->right!=nullptr){

                        int lp = findans(root->left,1,1);
                        int lnp = findans(root->left,0,0);
                        int rp = findans(root->right,1,1);
                        int rnp = findans(root->right,0,0);

                        ret = min(ret,lp+ rp);
                        ret = min(ret,lnp + rp);
                        ret = min(ret,lp + rnp);
                    }else if(root->left!=nullptr){
                        ret = min(ret,findans(root->left,1,1));
                    }else if(root->right!=nullptr){
                        ret = min(ret,findans(root->right,1,1) );
                    }

                }

                return ret;
            }
        }
    }
};

在这里插入图片描述
由于调用的子问题过多,样例超时


解法二:每次返回三个状态减少调用次数

参考
https://leetcode-cn.com/problems/binary-tree-cameras/solution/shou-hua-tu-jie-cong-di-gui-you-hua-dao-dong-tai-g/

调用一次返回三个状态,可以减少调用子问题的次数

#define min3(a,b,c)  min(min(a,b),c);
#define min4(a,b,c,d) min(min(min(a,b),c),d);
class Solution {
    
    public:
    int minArr(vector<int>arr){
        return min(min(arr[0],arr[1]),arr[2]);
    }
    
    int minCameraCover(TreeNode*root) {
        if (root == nullptr) return 0;
        vector<int> ret = findans(root);
        return min(ret[0],ret[2]);
    }

    vector<int> findans(TreeNode * root){
        
        // 0 not place cam not cover by father
        // 1 not place cam  cover by father
        // 2 place cam cover by self
        
        if(root==nullptr){
            return {0,0,1000000};   
        }
        vector<int> ret(3,0);
        vector<int> left = findans(root->left);
        vector<int> right = findans(root->right);
        
        ret[0] = min3(left[0] + right[2],left[2] + right[0],left[2] + right[2]);
        ret[1] = min4(left[0] + right[2],left[2] + right[0],left[2] + right[2],left[0] + right[0]);
        ret[2] = 1 + min4(left[1] + right[1],left[2] + right[1],left[1] + right[2],left[2] + right[2]);
        
        return ret;
    }
};

在这里插入图片描述


解法三:贪心构造

可以简单证明
这个问题的解是不唯一的
只要可以构造出来一种解即可
例如一个树只有两个节点,那么这两个位置放哪一个都可以
解法一超时间因为调用子问题过多
解法二虽然不超时,当时还是不够快,因为考虑了很多情况
构造:
我们使用贪心构造的办法,这个正确性需要证明,所以使用的时候需要谨慎
从下至上进行构造,叶子节点一定不要放置
两个子节点有一个放置了相机,那么父节点就不放置
两个子节点如果有一个没被监控,那么父节点需要放置
两个子节点如果都被监控了,那么父节点不放置相机

class Solution {
    public:
    int ans = 0;
    int minCameraCover(TreeNode*root) {
        if (root == nullptr) return 0;
        int ret = findans(root);
        if(ret==0){
            ans++;
        }
        return ans;
    }

    //返回 0 root 没有放置cam 并且没有被监控
    //返回 1 root 没有放置cam 并且被监控
    //返回 2 root 放置cam 并且被监控
    int findans(TreeNode*root){

        if(root==nullptr){
            return 1;
        }

        int left = findans(root->left);
        int right = findans(root->right);
        if( left==0 || right==0 ){
            ans ++;
            return 2;
        }
        if( left==2 || right==2 ){
            return 1;
        }
        return 0;
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值