You are given the root of a binary tree. We install cameras on the tree nodes where each camera at a node can monitor its parent, itself, and its immediate children.
Return the minimum number of cameras needed to monitor all nodes of the tree.
Example 1:
Input: root = [0,0,null,0,0]
Output: 1
Explanation: One camera is enough to monitor all nodes if placed as shown.
Example 2:
Input: root = [0,0,null,0,null,0,null,null,0]
Output: 2
Explanation: At least two cameras are needed to monitor all nodes of the tree. The above image shows one of the valid configurations of camera placement.
Constraints:
The number of nodes in the tree is in the range [1, 1000].
Node.val == 0
Solutions
Solution 1: Dynamic Programming (Tree DP)
Thinking
A camera covers itself, its parent, and its children; we want as few as possible. The optimum at a node depends on the children, so we distinguish “has a camera / covered by a child / uncovered”. Tree DP returns the three minima bottom-up; the root may not stay uncovered.
For each node, we define three states:
a: The current node has a camera
b: The current node does not have a camera, but is monitored by its children
c: The current node does not have a camera and is not monitored by its children
Next, we design a function \(\textit{dfs}(\textit{root})\), which will return an array of length 3, representing the minimum number of cameras in the subtree rooted at \(\textit{root}\) for the three states. The answer is \(\min(\textit{dfs}(\textit{root})[0], \textit{dfs}(\textit{root})[1])\).
The calculation process of the function \(\textit{dfs}(\textit{root})\) is as follows:
If \(\textit{root}\) is null, return \([\textit{inf}, 0, 0]\), where \(\textit{inf}\) represents a very large number, used to indicate an impossible situation.
Otherwise, we recursively calculate the left and right subtrees of \(\textit{root}\), obtaining \([la, lb, lc]\) and \([ra, rb, rc]\) respectively.
If the current node has a camera, then its left and right children must be in a monitored state, i.e., \(a = \min(la, lb, lc) + \min(ra, rb, rc) + 1\).
If the current node does not have a camera but is monitored by its children, then one or both of the children must have a camera, i.e., \(b = \min(la + rb, lb + ra, la + ra)\).
If the current node does not have a camera and is not monitored by its children, then the children must be monitored by their children, i.e., \(c = lb + rb\).
Finally, we return \([a, b, c]\).
The time complexity is \(O(n)\), and the space complexity is \(O(n)\), where \(n\) is the number of nodes in the binary tree.
1 2 3 4 5 6 7 8 91011121314151617181920
# Definition for a binary tree node.# class TreeNode:# def __init__(self, val=0, left=None, right=None):# self.val = val# self.left = left# self.right = rightclassSolution:defminCameraCover(self,root:Optional[TreeNode])->int:defdfs(root):ifrootisNone:returninf,0,0la,lb,lc=dfs(root.left)ra,rb,rc=dfs(root.right)a=min(la,lb,lc)+min(ra,rb,rc)+1b=min(la+rb,lb+ra,la+ra)c=lb+rbreturna,b,ca,b,_=dfs(root)returnmin(a,b)
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */funcminCameraCover(root*TreeNode)int{vardfsfunc(*TreeNode)(int,int,int)dfs=func(root*TreeNode)(int,int,int){ifroot==nil{return1<<29,0,0}la,lb,lc:=dfs(root.Left)ra,rb,rc:=dfs(root.Right)a:=1+min(la,min(lb,lc))+min(ra,min(rb,rc))b:=min(la+ra,min(la+rb,lb+ra))c:=lb+rbreturna,b,c}a,b,_:=dfs(root)returnmin(a,b)}
A camera covers itself, its parent, and its children, so the minimum depends on how each node is covered. Bottom-up, the three states are “has a camera”, “covered by a child”, and “uncovered”. On a short tree, returning those three minima is enough, and the root may not stay uncovered.
The tree can contain \(1000\) nodes. A left chain makes this postorder walk recurse once per node and overflow the call stack.
The three states of a node depend only on the three states of its children, so children must be finished before their parent.
An explicit stack performs that postorder walk. On entry it pushes an exit marker and the two children; on exit it writes the node’s states with the original three formulas. The answer is the smaller of the root’s first two states.
For each node, we define three states:
a: The current node has a camera
b: The current node does not have a camera, but is monitored by its children
c: The current node does not have a camera and is not monitored by its children
A null node corresponds to \((\textit{inf}, 0, 0)\), where \(\textit{inf}\) is a very large number used for an impossible situation.
We walk the binary tree in postorder with an explicit stack. On entry we push an exit marker, then the right child and the left child. On exit the children’s states are already stored as \([la, lb, lc]\) and \([ra, rb, rc]\).
If the current node has a camera, then its left and right children must be in a monitored state, i.e., \(a = \min(la, lb, lc) + \min(ra, rb, rc) + 1\).
If the current node does not have a camera but is monitored by its children, then one or both of the children must have a camera, i.e., \(b = \min(la + rb, lb + ra, la + ra)\).
If the current node does not have a camera and is not monitored by its children, then the children must be monitored by their children, i.e., \(c = lb + rb\).
The root must not stay uncovered, so the answer is \(\min(a, b)\).
The time complexity is \(O(n)\), and the space complexity is \(O(n)\), where \(n\) is the number of nodes in the binary tree.
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */funcminCameraCover(root*TreeNode)int{ifroot==nil{return0}constinf=1<<29sub:=map[*TreeNode][3]int{}typeframestruct{node*TreeNodestateint}stk:=[]frame{{root,0}}forlen(stk)>0{cur:=stk[len(stk)-1]stk=stk[:len(stk)-1]node:=cur.nodeifcur.state==0{stk=append(stk,frame{node,1})ifnode.Right!=nil{stk=append(stk,frame{node.Right,0})}ifnode.Left!=nil{stk=append(stk,frame{node.Left,0})}continue}l:=[3]int{inf,0,0}r:=[3]int{inf,0,0}ifnode.Left!=nil{l=sub[node.Left]}ifnode.Right!=nil{r=sub[node.Right]}a:=1+min(l[0],min(l[1],l[2]))+min(r[0],min(r[1],r[2]))b:=min(l[0]+r[0],min(l[0]+r[1],l[1]+r[0]))c:=l[1]+r[1]sub[node]=[3]int{a,b,c}}ans:=sub[root]returnmin(ans[0],ans[1])}