0
点赞
收藏
分享

微信扫一扫

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;
}
}
}
};

leetcode 968. 监控二叉树_职场和发展


由于调用的子问题过多,样例超时

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

参考
​​​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;
}
};

leetcode 968. 监控二叉树_leetcode_02

解法三:贪心构造

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

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;
}
};

leetcode 968. 监控二叉树_leetcode_03


举报

相关推荐

0 条评论