状态dfs搜索 968 监控二叉树
参考题解:https://leetcode-cn.com/problems/binary-tree-cameras/solution/jian-kong-er-cha-shu-by-leetcode-solution/(官方题解)
原题:https://leetcode-cn.com/problems/binary-tree-cameras/
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
输入:[0,0,null,0,0]
输出:1
解释:一台摄像头足以监控所有节点。
输入:[0,0,null,0,null,0,null,null,0]
输出:2
解释:需要至少两个摄像头来监视树的所有节点。
参考题解中的三种状态:
状态 a:root 必须放置摄像头的情况下,覆盖整棵树需要的摄像头数目。
状态 b:覆盖整棵树需要的摄像头数目,无论 root 是否放置摄像头。
状态 c:覆盖两棵子树需要的摄像头数目,无论节点root 本身是否被监控到。
对于状态a,
root已经放置了摄像头,那么root的左儿子和右儿子可以有监控也可以没有监控。所以如果需要覆盖整个树,root已经有了摄像头情况下(root和root的左儿子右儿子都被监控了),需要求的是对于左儿子和右儿子各自的子树被完全覆盖情况下需要的摄像头数,也就是儿子作为root后的状态c。所以a的值为1(root上的摄像头数)+lc+rc
对于状态b,
假如root放置了摄像头,等同于a;
假如root没有放置摄像头,如果root需要被监控到,那么左儿子和右儿子中至少有一个需要装上摄像头
所以有三种情况
1.左儿子装摄像头,右儿子没有装:此时左儿子作为新root需要的摄像头数是新root必须放置摄像头的数量,右儿子作为新root不用装摄像头但是要被覆盖的数量。
2.右儿子装摄像头,左儿子没有装:类似于1
3.左右儿子都装了摄像头:两个儿子都需要放置摄像头情况下的覆盖数量。即a+b
由abc定义可以知道,求三种情况的最小值可以这样: min(la+rb, lb+ra);
la+rb实际为 左儿子有摄像头右儿子没有摄像头 和 左儿子和右儿子都有摄像头的两种情况的最小值
lb+ra类似于上
所以最后的状态b=min(a, min(la+rb, lb+ra));
对于状态c
如果root装了摄像头,覆盖root的两个子树也就等同于a
如果root没有装摄像头,可以把root的两个子数从root中独立出来,也就是lb+rb
其实也可以按照root是否被监控来看,如果root被监控,覆盖root的两个子树也就等同于b,没有被监控同上。
所以c=min(a, lb+rb);或者c=min(b,lb+rb);
代码
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 typedef struct status{ 13 int a, b, c; 14 status(){} 15 status(int a, int b, int c):a(a), b(b), c(c){} 16 }Status; 17 Status dfs(TreeNode* root){ 18 if(root==NULL){ 19 return Status(INT_MAX/2, 0, 0); 20 } 21 Status l=dfs(root->left); 22 Status r=dfs(root->right); 23 24 int a=1+l.c+r.c; 25 int b=min(a, min(l.a+r.b, l.b+r.a)); 26 int c=min(b, l.b+r.b); 27 return Status(a,b,c); 28 } 29 30 int minCameraCover(TreeNode* root) { 31 Status res=dfs(root); 32 return res.b; 33 } 34 };