45
45
46
46
## 解法
47
47
48
- ### 方法一
48
+ ### 方法一:并查集
49
+
50
+ 判断是否是树,需要满足以下两个条件:
51
+
52
+ 1 . 边的数量等于节点数减一;
53
+ 2 . 不存在环。
54
+
55
+ 我们可以使用并查集来判断是否存在环。遍历边,如果两个节点已经在同一个集合中,说明存在环。否则,我们将两个节点合并到同一个集合中。然后将连通分量的数量减一,最后判断连通分量的数量是否为 $1$。
56
+
57
+ 时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是节点数。
49
58
50
59
<!-- tabs:start -->
51
60
52
61
``` python
53
62
class Solution :
54
63
def validTree (self , n : int , edges : List[List[int ]]) -> bool :
55
- def find (x ) :
64
+ def find (x : int ) -> int :
56
65
if p[x] != x:
57
66
p[x] = find(p[x])
58
67
return p[x]
59
68
60
69
p = list (range (n))
61
70
for a, b in edges:
62
- if find(a) == find(b):
71
+ pa, pb = find(a), find(b)
72
+ if pa == pb:
63
73
return False
64
- p[find(a) ] = find(b)
74
+ p[pa ] = pb
65
75
n -= 1
66
76
return n == 1
67
77
```
@@ -75,12 +85,12 @@ class Solution {
75
85
for (int i = 0 ; i < n; ++ i) {
76
86
p[i] = i;
77
87
}
78
- for (int [] e : edges) {
79
- int a = e[0 ], b = e[1 ];
80
- if (find(a) == find(b) ) {
88
+ for (var e : edges) {
89
+ int pa = find( e[0 ]), pb = find( e[1 ]) ;
90
+ if (pa == pb ) {
81
91
return false ;
82
92
}
83
- p[find(a) ] = find(b) ;
93
+ p[pa ] = pb ;
84
94
-- n;
85
95
}
86
96
return n == 1 ;
@@ -98,24 +108,25 @@ class Solution {
98
108
``` cpp
99
109
class Solution {
100
110
public:
101
- vector<int > p;
102
-
103
111
bool validTree(int n, vector<vector<int >>& edges) {
104
- p.resize(n);
105
- for (int i = 0; i < n; ++i) p[i] = i;
112
+ vector<int > p(n);
113
+ iota(p.begin(), p.end(), 0);
114
+ function<int(int)> find = [ &] (int x) {
115
+ if (p[ x] != x) {
116
+ p[ x] = find(p[ x] );
117
+ }
118
+ return p[ x] ;
119
+ };
106
120
for (auto& e : edges) {
107
- int a = e[0], b = e[1];
108
- if (find(a) == find(b)) return 0;
109
- p[find(a)] = find(b);
121
+ int pa = find(e[ 0] ), pb = find(e[ 1] );
122
+ if (pa == pb) {
123
+ return false;
124
+ }
125
+ p[ pa] = pb;
110
126
--n;
111
127
}
112
128
return n == 1;
113
129
}
114
-
115
- int find (int x) {
116
- if (p[ x] != x) p[ x] = find(p[ x] );
117
- return p[ x] ;
118
- }
119
130
};
120
131
```
121
132
@@ -125,19 +136,19 @@ func validTree(n int, edges [][]int) bool {
125
136
for i := range p {
126
137
p[i] = i
127
138
}
128
- var find func(x int) int
139
+ var find func(int) int
129
140
find = func(x int) int {
130
141
if p[x] != x {
131
142
p[x] = find(p[x])
132
143
}
133
144
return p[x]
134
145
}
135
146
for _, e := range edges {
136
- a, b := e[0], e[1]
137
- if find(a) == find(b) {
147
+ pa, pb := find( e[0]), find( e[1])
148
+ if pa == pb {
138
149
return false
139
150
}
140
- p[find(a) ] = find(b)
151
+ p[pa ] = pb
141
152
n--
142
153
}
143
154
return n == 1
@@ -151,24 +162,170 @@ func validTree(n int, edges [][]int) bool {
151
162
* @return {boolean}
152
163
*/
153
164
var validTree = function (n , edges ) {
154
- let p = new Array (n);
155
- for (let i = 0 ; i < n; ++ i) {
156
- p[i] = i;
157
- }
158
- function find (x ) {
159
- if (p[x] != x) {
165
+ const p = Array .from ({ length: n }, (_ , i ) => i);
166
+ const find = x => {
167
+ if (p[x] !== x) {
160
168
p[x] = find (p[x]);
161
169
}
162
170
return p[x];
163
- }
171
+ };
164
172
for (const [a , b ] of edges) {
165
- if (find (a) == find (b)) {
173
+ const pa = find (a);
174
+ const pb = find (b);
175
+ if (pa === pb) {
166
176
return false ;
167
177
}
168
- p[find (a) ] = find (b) ;
178
+ p[pa ] = pb ;
169
179
-- n;
170
180
}
171
- return n == 1 ;
181
+ return n === 1 ;
182
+ };
183
+ ```
184
+
185
+ <!-- tabs: end -->
186
+
187
+ ### 方法二:DFS
188
+
189
+ 我们也可以使用深度优先搜索来判断是否存在环。我们可以使用一个数组 $vis$ 来记录访问过的节点,搜索时,我们先将节点标记为已访问,然后遍历与该节点相邻的节点,如果相邻节点已经访问过,则跳过,否则递归访问相邻节点。最后,我们判断是否所有节点都被访问过,如果有未访问过的节点,说明无法构成树,返回 ` false ` 。
190
+
191
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是节点数。
192
+
193
+ <!-- tabs: start -->
194
+
195
+ ``` python
196
+ class Solution :
197
+ def validTree (self , n : int , edges : List[List[int ]]) -> bool :
198
+ def dfs (i : int ):
199
+ vis.add(i)
200
+ for j in g[i]:
201
+ if j not in vis:
202
+ dfs(j)
203
+
204
+ if len (edges) != n - 1 :
205
+ return False
206
+ g = [[] for _ in range (n)]
207
+ for a, b in edges:
208
+ g[a].append(b)
209
+ g[b].append(a)
210
+ vis = set ()
211
+ dfs(0 )
212
+ return len (vis) == n
213
+ ```
214
+
215
+ ``` java
216
+ class Solution {
217
+ private List<Integer > [] g;
218
+ private Set<Integer > vis = new HashSet<> ();
219
+
220
+ public boolean validTree (int n , int [][] edges ) {
221
+ if (edges. length != n - 1 ) {
222
+ return false ;
223
+ }
224
+ g = new List [n];
225
+ Arrays . setAll(g, k - > new ArrayList<> ());
226
+ for (var e : edges) {
227
+ int a = e[0 ], b = e[1 ];
228
+ g[a]. add(b);
229
+ g[b]. add(a);
230
+ }
231
+ dfs(0 );
232
+ return vis. size() == n;
233
+ }
234
+
235
+ private void dfs (int i ) {
236
+ vis. add(i);
237
+ for (int j : g[i]) {
238
+ if (! vis. contains(j)) {
239
+ dfs(j);
240
+ }
241
+ }
242
+ }
243
+ }
244
+ ```
245
+
246
+ ``` cpp
247
+ class Solution {
248
+ public:
249
+ bool validTree(int n, vector<vector<int >>& edges) {
250
+ if (edges.size() != n - 1) {
251
+ return false;
252
+ }
253
+ vector<int > g[ n] ;
254
+ vector<int > vis(n);
255
+ function<void(int)> dfs = [ &] (int i) {
256
+ vis[ i] = true;
257
+ --n;
258
+ for (int j : g[ i] ) {
259
+ if (!vis[ j] ) {
260
+ dfs(j);
261
+ }
262
+ }
263
+ };
264
+ for (auto& e : edges) {
265
+ int a = e[ 0] , b = e[ 1] ;
266
+ g[ a] .push_back(b);
267
+ g[ b] .push_back(a);
268
+ }
269
+ dfs(0);
270
+ return n == 0;
271
+ }
272
+ };
273
+ ```
274
+
275
+ ```go
276
+ func validTree(n int, edges [][]int) bool {
277
+ if len(edges) != n-1 {
278
+ return false
279
+ }
280
+ g := make([][]int, n)
281
+ vis := make([]bool, n)
282
+ for _, e := range edges {
283
+ a, b := e[0], e[1]
284
+ g[a] = append(g[a], b)
285
+ g[b] = append(g[b], a)
286
+ }
287
+ var dfs func(int)
288
+ dfs = func(i int) {
289
+ vis[i] = true
290
+ n--
291
+ for _, j := range g[i] {
292
+ if !vis[j] {
293
+ dfs(j)
294
+ }
295
+ }
296
+ }
297
+ dfs(0)
298
+ return n == 0
299
+ }
300
+ ```
301
+
302
+ ``` js
303
+ /**
304
+ * @param {number} n
305
+ * @param {number[][]} edges
306
+ * @return {boolean}
307
+ */
308
+ var validTree = function (n , edges ) {
309
+ if (edges .length !== n - 1 ) {
310
+ return false ;
311
+ }
312
+ const g = Array .from ({ length: n }, () => []);
313
+ const vis = Array .from ({ length: n }, () => false );
314
+ for (const [a , b ] of edges) {
315
+ g[a].push (b);
316
+ g[b].push (a);
317
+ }
318
+ const dfs = i => {
319
+ vis[i] = true ;
320
+ -- n;
321
+ for (const j of g[i]) {
322
+ if (! vis[j]) {
323
+ dfs (j);
324
+ }
325
+ }
326
+ };
327
+ dfs (0 );
328
+ return n === 0 ;
172
329
};
173
330
```
174
331
0 commit comments