• 监控二叉树


    题目来源:https://leetcode-cn.com/problems/binary-tree-cameras/

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

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

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

    示例 1:

     

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

     

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

    提示:

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

    题解:暴力超时:遍历各个节点,每个节点两种情况,亮灯或者不亮灯(代表相机),是否亮灯影响下面节点,所以加一个遍历参数间隔,间隔最大可以为2,当为2时必然要亮灯,当深度为1时两个孩子亮1个即可,取各情况的最小值即为最优解。但是节点数量最大为1000,暴力时间复杂度log(2*2)n,肯定超时,应该是动态规划解,后面补充正确解法。

     1 public class 监控二叉树968 {
     2 
     3     public int minCameraCover(TreeNode root, int interval) {
     4 
     5         if(root == null){
     6             return 0;
     7         }
     8         if(interval == 1 && root.left == null && root.right == null){
     9             //当没有孩子节点,父节点也没有照到,则亮灯
    10             root.val = 1;
    11             return 1;
    12         }
    13 
    14         if(interval == 1 && root.left != null && root.right != null){
    15             // 当有1个间隔,两个孩子,两个孩子中的一个能照到此节点就好
    16             root.val = 1;
    17             int x = minCameraCover(root.left, 0) + minCameraCover(root.right, 0) + 1;
    18             root.val = 0;
    19             int y = minCameraCover(root.left, interval) + minCameraCover(root.right, interval + 1);
    20             int z = minCameraCover(root.left, interval + 1) + minCameraCover(root.right, interval);
    21             // 此节点可亮可不亮,三种情况对比,选择最优解
    22             if(x < Math.min(y, z)){
    23                 root.val = 1;
    24                 return x;
    25             } else {
    26                 return Math.min(y, z);
    27             }
    28         }
    29 
    30         if(interval == 2){
    31             //深度为2,一点要亮灯
    32             root.val = 1;
    33             return minCameraCover(root.left, 0) + minCameraCover(root.right, 0) + 1;
    34         }else {
    35             // 深度为1,此节点可亮可不亮
    36             root.val = 1;
    37             int x = minCameraCover(root.left, 0) + minCameraCover(root.right, 0) + 1;
    38             root.val = 0;
    39             int y = minCameraCover(root.left, interval + 1) + minCameraCover(root.right, interval + 1);
    40             if(x < y){
    41                 // 找到最小的情况
    42                 root.val = 1;
    43                 return x;
    44             } else {
    45                 return y;
    46             }
    47 
    48         }
    49     }
    50 
    51 
    52     public int minCameraCover(TreeNode root){
    53         return minCameraCover(root, 1);
    54     }
    55 
    56     private static TreeNode buildTree(){
    57         int nextInt = Input.cin.nextInt();
    58         if(nextInt == 0){
    59             TreeNode treeNode = new TreeNode(0);
    60             treeNode.left = buildTree();
    61             treeNode.right = buildTree();
    62             return treeNode;
    63         }
    64         return null;
    65     }
    66     public static void main(String[] args) {
    67         TreeNode treeNode = buildTree();
    68         int x = new 监控二叉树968().minCameraCover(treeNode);
    69         System.out.println(x);
    70     }
    71 }

    正确解法:

    前面的暴力明显反应了父亲,当前节点,和孩子的关系,那么可以将这些关系总结为3个状态,1. 当前节点有相机,2. 当前节点放不放都行(全局最优),3. 两个子树都被覆盖

    然后遍历,在每个阶段都求最优解:

    第1个状态:左右子树的第三个状态之和 + 当前节点的相机

    第3个状态:左右子树的全局最优和

    第2个状态: 左树有相机+右树最优  或   左树最优+右树有相机

    得到最终代码:

     1 public class 监控二叉树968 {
     2 
     3 
     4     public int[] trave(TreeNode root){
     5         if(root == null){
     6             //当前root有相机, 当前root放或者不放摄像头都行,两个子树被覆盖(不管root)
     7             return new int[]{Integer.MAX_VALUE / 2, 0, 0};
     8         }
     9         int[] left = trave(root.left);
    10         int[] right = trave(root.right);
    11         int[] array = new int[3];
    12         //两个孩子都被他们的孩子监控的最优解 + 1(有相机)
    13         array[0] = left[2] + right[2] + 1;
    14         // 左孩子有相机 或者右孩子有相机时分别加上另外一个孩子的最优解
    15         array[1] = Math.min(array[0], Math.min(left[0] + right[1], left[1] + right[0]));
    16         //不管当前节点,取孩子们的最优解
    17         array[2] = Math.min(array[0], left[1] + right[1]);
    18         return array;
    19     }
    20     public int minCameraCover(TreeNode root){
    21         int[] trave = trave(root);
    22         return trave[1];
    23     }
    24 
    25     private static TreeNode buildTree(){
    26         int nextInt = Input.cin.nextInt();
    27         if(nextInt == 0){
    28             TreeNode treeNode = new TreeNode(0);
    29             treeNode.left = buildTree();
    30             treeNode.right = buildTree();
    31             return treeNode;
    32         }
    33         return null;
    34     }
    35     public static void main(String[] args) {
    36         TreeNode treeNode = buildTree();
    37         int x = new 监控二叉树968().minCameraCover(treeNode);
    38         System.out.println(x);
    39     }
    40 }

    转载请注明地址:http://www.cnblogs.com/handsomecui/

  • 相关阅读:
    Bootstrap_让Bootstrap轮播插件carousel支持左右滑动手势的三种方法
    JAVA_用Java来获取访问者真实的IP地址
    Html5_移动前端不得不了解的html5 head 头标签
    ThinkPad_T430重装系统
    JavaScript_JS判断客户端是否是iOS或者Android
    Html5_禁止Html5在手机上屏幕页面缩放
    HttpClient_httpclient 4.3.1 post get的工具类
    HttpClient_使用httpclient必须知道的参数设置及代码写法、存在的风险
    LATEX数学公式基本语法
    为WLW开发Latex公式插件
  • 原文地址:https://www.cnblogs.com/handsomecui/p/13714939.html
Copyright © 2020-2023  润新知