监控二叉树

题目来源: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/

posted @ 2020-09-22 21:15  handsomecui  阅读(220)  评论(0编辑  收藏  举报