题目
26年7月8日(首刷看解)
func minCameraCover(root *TreeNode) int {
result:=0
var dfs func(root *TreeNode) int
dfs=func (root *TreeNode) int {
//0无覆盖,1有摄像头,2有覆盖
if root==nil{
return 2
}
left:=dfs(root.Left)
right:=dfs(root.Right)
if left==2&&right==2{
return 0
}
if left==0||right==0{
result++
return 1
}
if left==1||right==1{
return 2
}
return -1
}
if dfs(root)==0{
result++
}
return result
}
思路
这道题我最开始其实脑子里只有一点模糊的概念,想到可能会使用标记状态,但是见过的题还有功底确实浅,就不知道怎么做
思路就是我们很容易想到如果这个摄像头放在叶子节点,肯定就亏了,因为放在叶子节点的父亲那管的范围更宽。
所以我们要考虑两个问题1.如何遍历 2.如何确定什么时候放摄像头
那么我们想到的其实最好是从下往上遍历,后序遍历最好。
然后我们想每一个节点其实一共有一个状态,0.未覆盖 1.摄像头 2.覆盖
既然从下往上,我们要确定的就是是叶子节点的父节点装摄像头,然后每隔一层的第二层继续装一个大概的思路就如此。
我们后序遍历还是有一个模版的,就是终止条件,到递归调用到单层逻辑
1.终止条件,一般是遇到空节点返回,这道题我们要知道我们是需要根据子节点的情况来确定当前节点应该有的状态, 比如子节点是摄像头1,那么我父节点不用向子节点负责,不用装摄像头,而且被覆盖了。就是2
这里我一开始也疑问,那么叶子结点的状态判断是根据空节点的状态,空节点有什么状态?
这里其实我们想如果要达到我们的目标,我们用一个倒推的方法,如果叶子节点的父节点为1,那么叶子节点就必须为0,叶子节点为0,那么空节点就为2,(其实是有点绕的,可能我理解的也不够,)
所以终止条件设为
if root==nil{ return 2 }
再递归调用
**然后单层逻辑,就是关键 **
其实我们最容易想到的就是如果子节点但凡有一个为0,我们父节点都要负责人,设置1装一个摄像头,然后如果子节点为1(有摄像头),我们不用管了父节点躺平了,在子节点的照料下变成2,如果子节点为2,我们父节点也躺平了,不用管,但是我们没有受到子节点的照料,为0(未覆盖),由爷爷来管爸爸。哈哈就是爸爸管儿子。然后一层一层往上
更为具体的逻辑就看下面
其实最后还有一个情况4,我们说爸爸管儿子,那最高级的根节点已经没有爸爸了,相当于要单独判断了这一点要记住
其实这种循环体系,开头和结尾都有可能要特殊判断,就像有些题目必须要初始化,才能让整个逻辑体系自转下去