给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。

计算监控树的所有节点所需的最小摄像头数量。

 

示例 1:

968. Binary Tree Cameras 监控二叉树_子树

输入:[0,0,null,0,0]
输出:1
解释:如图所示,一台摄像头足以监控所有节点。

示例 2:

968. Binary Tree Cameras 监控二叉树_二叉树_02

输入:[0,0,null,0,null,0,null,null,0]
输出:2
解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。


提示:

  1. 给定树的节点数的范围是 [1, 1000]
  2. 每个节点的值都是 0。

递归

本题以二叉树为背景,不难想到用递归的方式求解。本题的难度在于如何从左、右子树的状态,推导出父节点的状态。

为了表述方便,我们约定:如果某棵树的所有节点都被监控,则称该树被「覆盖」。

假设当前节点为 root\textit{root}root,其左右孩子为 left,right\textit{left}, \textit{right}left,right。如果要覆盖以 root\textit{root}root 为根的树,有两种情况:

  • 若在 root\textit{root}root 处安放摄像头,则孩子 left,right\textit{left}, \textit{right}left,right 一定也会被监控到。此时,只需要保证 left\textit{left}left 的两棵子树被覆盖,同时保证 right\textit{right}right 的两棵子树也被覆盖即可。
  • 否则, 如果 root\textit{root}root 处不安放摄像头,则除了覆盖 root\textit{root}root 的两棵子树之外,孩子 left,right\textit{left}, \textit{right}left,right 之一必须要安装摄像头,从而保证 root\textit{root}root 会被监控到。

根据上面的讨论,能够分析出,对于每个节点 root\textit{root}root ,需要维护三种类型的状态:

  • 状态 aaaroot\textit{root}root 必须放置摄像头的情况下,覆盖整棵树需要的摄像头数目。
  • 状态 bbb:覆盖整棵树需要的摄像头数目,无论 root\textit{root}root 是否放置摄像头。
  • 状态 ccc:覆盖两棵子树需要的摄像头数目,无论节点 root\textit{root}root 本身是否被监控到。

根据它们的定义,一定有 a≥b≥ca \geq b \geq cabc

对于节点 root\textit{root}root 而言,设其左右孩子 left,right\textit{left}, \textit{right}left,right 对应的状态变量分别为 (la,lb,lc)(l_a,l_b,l_c)(la,lb,lc) 以及 (ra,rb,rc)(r_a,r_b,r_c)(ra,rb,rc)。根据一开始的讨论,我们已经得到了求解 a,ba,ba,b 的过程:

  • a=lc+rc+1a = l_c + r_c + 1a=lc+rc+1
  • b=min⁡(a,min⁡(la+rb,ra+lb))b = \min(a, \min(l_a + r_b, r_a + l_b))b=min(a,min(la+rb,ra+lb))

对于 ccc 而言,要保证两棵子树被完全覆盖,要么 root\textit{root}root 处放置一个摄像头,需要的摄像头数目为 aaa;要么 root\textit{root}root 处不放置摄像头,此时两棵子树分别保证自己被覆盖,需要的摄像头数目为 lb+rbl_b + r_blb+rb

需要额外注意的是,对于 root\textit{root}root 而言,如果其某个孩子为空,则不能通过在该孩子处放置摄像头的方式,监控到当前节点。因此,该孩子对应的变量 aaa 应当返回一个大整数,用于标识不可能的情形。

最终,根节点的状态变量 bbb 即为要求出的答案。

代码

	def minCameraCover(self, root: TreeNode) -> int:
		def dfs(root: TreeNode) -> List[int]:
			if not root:
				return [float('inf'), 0, 0]

			la, lb, lc = dfs(root.left)
			ra, rb, rc = dfs(root.right)
			a = lc + rc + 1
			b = min(a, la + rb, ra + lb)
			c = min(a, lb + rb)
			return [a, b, c]

		a, b, c = dfs(root)
		return b