[路飞]_leetcode-968-监控二叉树

125 阅读2分钟

题目描述

[题目地址]

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

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

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

示例 1:

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

示例 2:

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

提示:

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

动画演示如下:

leetcode-968-监控二叉树.gif

动态规划求解

涉及到求最优解的题,都可以用动态规划解题

有了题解1的基础,这里我们可以推导出状态定义如下:

dp[i][j] 表示监控以 j 为根节点的子树所需要的摄像头数量
i 表示 j 的父节点,0 表示当前节点不放置摄像头,1 表示当前节点放置摄像头
每个节点有如下四种状态:
dp[0][0] 覆盖当前子树父节点不放置摄像头,根节点不放置摄像头的摄像头数量
dp[0][1] 覆盖当前子树父节点不放置摄像头,根节点放置摄像头的摄像头数量
dp[1][0] 覆盖当前子树父节点放置摄像头,根节点不放置摄像头的摄像头数量
dp[1][1] 覆盖当前子树父节点放置摄像头,根节点放置摄像头的摄像头数量

状态转移方程如下:

l 为左子树 dp,r 为右子树 dp
dp[0][0] = Math.min(l[0][0]+r[0][1],l[0][1]+r[0][0],l[0][1]+r[0][1]);
dp[1][0] = Math.min(dp[0][0],l[0][0]+r[0][0]);
dp[0][1] = Math.min(l[1][0]+r[1][0],l[1][1]+r[1][0],l[1][0]+r[1][1],l[1][1]+r[1][1])+1;
dp[1][1] = dp[0][1];

代码如下

var minCameraCover = function(root) {
  function getDp(root){
    const dp = [[],[]];
    if(root === null){
      dp[0][0] = 0;
      dp[0][1] = 10000;
      dp[1][0] = 0;
      dp[1][1] = 10000;
      return dp;
    }
    if(root.left===null&&root.right===null){
      dp[0][0] = 10000;
      dp[0][1] = 1;
      dp[1][0] = 0;
      dp[1][1] = 1;
      return dp;
    }
    const l = getDp(root.left),
    r = getDp(root.right);
    dp[0][0] = Math.min(l[0][0]+r[0][1],l[0][1]+r[0][0],l[0][1]+r[0][1]);
    dp[1][0] = Math.min(dp[0][0],l[0][0]+r[0][0]);
    dp[0][1] = Math.min(l[1][0]+r[1][0],l[1][1]+r[1][0],l[1][0]+r[1][1],l[1][1]+r[1][1])+1;
    dp[1][1] = dp[0][1];
    return dp;
  }
  const dp = getDp(root);
  return Math.min(dp[0][1],dp[0][0]);
}

至此我们就完成了 leetcode-968-监控二叉树