44
44
45
45
<!-- 这里可写通用的实现逻辑 -->
46
46
47
- 贪心 + DFS。
47
+ ** 方法一:动态规划(树形 DP) **
48
48
49
- 我们知道,
49
+ 对于每个节点,我们定义三种状态:
50
50
51
- 1 . 如果在叶子节点放置摄像头,摄像头会覆盖当前叶子节点以及它的父节点;
52
- 1 . 如果在非叶子节点放置摄像头,摄像头会覆盖当前节点、它的子节点以及它的父节点。
51
+ - ` a ` :当前节点有摄像头
52
+ - ` b ` :当前节点无摄像头,但被子节点监控
53
+ - ` c ` :当前节点无摄像头,也没被子节点监控
53
54
54
- 第二种方案始终优于第一种方案 。
55
+ 接下来,我们设计一个函数 $dfs(root)$,它将返回一个长度为 3 的数组,表示以 ` root ` 为根的子树中,三种状态下的最小摄像头数量。那么答案就是 $\min(dfs(root) [ 0 ] , dfs(root) [ 1 ] )$ 。
55
56
56
- 因此,一种贪心的解法是,将摄像头放置在叶子节点的父节点上,然后移除所有被覆盖的节点,重复这一步骤,直至所有节点被移除。
57
+ 函数 $dfs(root)$ 的计算过程如下:
57
58
58
- 我们用数字 0, 1, 2 表示每个节点可能的三种状态,
59
+ 如果 ` root ` 为空,则返回 $ [ inf, 0, 0 ] $,其中 ` inf ` 表示一个很大的数,它用于表示不可能的情况。
59
60
60
- - 0: 叶子节点
61
- - 1: 叶子节点的父节点,并且放置了摄像头
62
- - 2: 没放置摄像头,但是被摄像头覆盖
61
+ 否则,我们递归计算 ` root ` 的左右子树,分别得到 $[ la, lb, lc] $ 和 $[ ra, rb, rc] $。
63
62
64
- 定义 dfs(node) 返回每个节点的状态,对于每个节点,
63
+ - 如果当前节点有摄像头,那么它的左右节点必须都是被监控的状态,即 $a = \min(la, lb, lc) + \min(ra, rb, rc) + 1$。
64
+ - 如果当前节点无摄像头,但被子节点监控,那么子节点可以是其中之一或者两个都有摄像头,即 $b = \min(la + rb, lb + ra, la + ra)$。
65
+ - 如果当前节点无摄像头,也没被子节点监控,那么子节点必须被其子节点监控,即 $c = lb + rb$。
65
66
66
- 1 . 如果存在子节点,并且是叶子节点(` left == 0 || right == 0 ` ),那么该节点需要放置摄像头,累加摄像头 ans,返回 1;
67
- 1 . 如果存在子节点,并且子节点放置了摄像头(` left == 1 || right == 1 ` ),那么该节点可以直接被覆盖,返回 2;
68
- 1 . 否则把当前节点视为叶子节点,继续向上递归。
67
+ 最后,我们返回 $[ a, b, c] $。
69
68
70
- 判断 ` dfs(root) ` 结果,若等于 0,说明还存在当前这一个叶子节点未被覆盖,摄像头数量 ans + 1 并返回,否则返回 ans 。
69
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点数 。
71
70
72
71
<!-- tabs:start -->
73
72
83
82
# self.left = left
84
83
# self.right = right
85
84
class Solution :
86
- def minCameraCover (self , root : TreeNode) -> int :
85
+ def minCameraCover (self , root : Optional[ TreeNode] ) -> int :
87
86
def dfs (root ):
88
- nonlocal ans
89
87
if root is None :
90
- return 2
91
- left, right = dfs(root.left), dfs(root.right)
92
- if left == 0 or right == 0 :
93
- ans += 1
94
- return 1
95
- return 2 if left == 1 or right == 1 else 0
96
-
97
- ans = 0
98
- return (dfs(root) == 0 ) + ans
88
+ return inf, 0 , 0
89
+ la, lb, lc = dfs(root.left)
90
+ ra, rb, rc = dfs(root.right)
91
+ a = min (la, lb, lc) + min (ra, rb, rc) + 1
92
+ b = min (la + rb, lb + ra, la + ra)
93
+ c = lb + rb
94
+ return a, b, c
95
+
96
+ a, b, _ = dfs(root)
97
+ return min (a, b)
99
98
```
100
99
101
100
### ** Java**
@@ -119,28 +118,21 @@ class Solution:
119
118
* }
120
119
*/
121
120
class Solution {
122
-
123
- private int ans;
124
-
125
121
public int minCameraCover (TreeNode root ) {
126
- ans = 0 ;
127
- return (dfs(root) == 0 ) ? ans + 1 : ans ;
122
+ int [] ans = dfs(root) ;
123
+ return Math . min(ans[ 0 ], ans[ 1 ]) ;
128
124
}
129
125
130
- private int dfs (TreeNode root ) {
126
+ private int [] dfs (TreeNode root ) {
131
127
if (root == null ) {
132
- return 2 ;
133
- }
134
- int left = dfs(root. left);
135
- int right = dfs(root. right);
136
- if (left == 0 || right == 0 ) {
137
- ++ ans;
138
- return 1 ;
139
- }
140
- if (left == 1 || right == 1 ) {
141
- return 2 ;
128
+ return new int [] {1 << 29 , 0 , 0 };
142
129
}
143
- return 0 ;
130
+ var l = dfs(root. left);
131
+ var r = dfs(root. right);
132
+ int a = 1 + Math . min(Math . min(l[0 ], l[1 ]), l[2 ]) + Math . min(Math . min(r[0 ], r[1 ]), r[2 ]);
133
+ int b = Math . min(Math . min(l[0 ] + r[1 ], l[1 ] + r[0 ]), l[0 ] + r[0 ]);
134
+ int c = l[1 ] + r[1 ];
135
+ return new int [] {a, b, c};
144
136
}
145
137
}
146
138
```
@@ -159,26 +151,28 @@ class Solution {
159
151
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
160
152
* };
161
153
*/
154
+ struct Status {
155
+ int a, b, c;
156
+ };
157
+
162
158
class Solution {
163
159
public:
164
- int ans;
165
-
166
160
int minCameraCover(TreeNode* root) {
167
- ans = 0;
168
- if (dfs(root) == 0) return ans + 1;
169
- return ans;
161
+ auto [ a, b, _ ] = dfs(root);
162
+ return min(a, b);
170
163
}
171
164
172
- int dfs (TreeNode* root) {
173
- if (!root) return 2;
174
- int left = dfs(root->left), right = dfs(root->right);
175
- if (left == 0 || right == 0) {
176
- ++ans;
177
- return 1;
165
+ Status dfs(TreeNode* root) {
166
+ if (!root) {
167
+ return {1 << 29, 0, 0};
178
168
}
179
- if (left == 1 || right == 1) return 2;
180
- return 0;
181
- }
169
+ auto [la, lb, lc] = dfs(root->left);
170
+ auto [ra, rb, rc] = dfs(root->right);
171
+ int a = 1 + min({la, lb, lc}) + min({ra, rb, rc});
172
+ int b = min({la + ra, la + rb, lb + ra});
173
+ int c = lb + rb;
174
+ return {a, b, c};
175
+ };
182
176
};
183
177
```
184
178
@@ -194,27 +188,68 @@ public:
194
188
* }
195
189
*/
196
190
func minCameraCover (root *TreeNode ) int {
197
- ans := 0
198
- var dfs func(root *TreeNode) int
199
- dfs = func(root *TreeNode) int {
191
+ var dfs func (*TreeNode) (int , int , int )
192
+ dfs = func (root *TreeNode) (int , int , int ) {
200
193
if root == nil {
201
- return 2
202
- }
203
- left, right := dfs(root.Left), dfs(root.Right)
204
- if left == 0 || right == 0 {
205
- ans++
206
- return 1
194
+ return 1 << 29 , 0 , 0
207
195
}
208
- if left == 1 || right == 1 {
209
- return 2
210
- }
211
- return 0
196
+ la , lb , lc := dfs (root.Left )
197
+ ra , rb , rc := dfs (root.Right )
198
+ a := 1 + min (la, min (lb, lc)) + min (ra, min (rb, rc))
199
+ b := min (la+ra, min (la+rb, lb+ra))
200
+ c := lb + rb
201
+ return a, b, c
212
202
}
213
- if dfs(root) == 0 {
214
- return ans + 1
203
+ a , b , _ := dfs (root)
204
+ return min (a, b)
205
+ }
206
+
207
+ func min (a , b int ) int {
208
+ if a < b {
209
+ return a
215
210
}
216
- return ans
211
+ return b
212
+ }
213
+ ```
214
+
215
+ ### ** TypeScript**
216
+
217
+ ``` ts
218
+ /**
219
+ * Definition for a binary tree node.
220
+ * class TreeNode {
221
+ * val: number
222
+ * left: TreeNode | null
223
+ * right: TreeNode | null
224
+ * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
225
+ * this.val = (val===undefined ? 0 : val)
226
+ * this.left = (left===undefined ? null : left)
227
+ * this.right = (right===undefined ? null : right)
228
+ * }
229
+ * }
230
+ */
231
+
232
+ function minCameraCover(root : TreeNode | null ): number {
233
+ const dfs = (root : TreeNode | null ): number [] => {
234
+ if (! root ) {
235
+ return [1 << 29 , 0 , 0 ];
236
+ }
237
+ const [la, lb, lc] = dfs (root .left );
238
+ const [ra, rb, rc] = dfs (root .right );
239
+ const a = 1 + Math .min (la , lb , lc ) + Math .min (ra , rb , rc );
240
+ const b = Math .min (la + ra , la + rb , lb + ra );
241
+ const c = lb + rb ;
242
+ return [a , b , c ];
243
+ };
244
+ const [a, b, _] = dfs (root );
245
+ return Math .min (a , b );
217
246
}
218
247
```
219
248
249
+ ### ** ...**
250
+
251
+ ```
252
+
253
+ ```
254
+
220
255
<!-- tabs:end -->
0 commit comments