4545
4646## 解法
4747
48- ### 方法一
48+ ### 方法一:并查集
49+
50+ 判断是否是树,需要满足以下两个条件:
51+
52+ 1 . 边的数量等于节点数减一;
53+ 2 . 不存在环。
54+
55+ 我们可以使用并查集来判断是否存在环。遍历边,如果两个节点已经在同一个集合中,说明存在环。否则,我们将两个节点合并到同一个集合中。然后将连通分量的数量减一,最后判断连通分量的数量是否为 $1$。
56+
57+ 时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是节点数。
4958
5059<!-- tabs:start -->
5160
5261``` python
5362class Solution :
5463 def validTree (self , n : int , edges : List[List[int ]]) -> bool :
55- def find (x ) :
64+ def find (x : int ) -> int :
5665 if p[x] != x:
5766 p[x] = find(p[x])
5867 return p[x]
5968
6069 p = list (range (n))
6170 for a, b in edges:
62- if find(a) == find(b):
71+ pa, pb = find(a), find(b)
72+ if pa == pb:
6373 return False
64- p[find(a) ] = find(b)
74+ p[pa ] = pb
6575 n -= 1
6676 return n == 1
6777```
@@ -75,12 +85,12 @@ class Solution {
7585 for (int i = 0 ; i < n; ++ i) {
7686 p[i] = i;
7787 }
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 ) {
8191 return false ;
8292 }
83- p[find(a) ] = find(b) ;
93+ p[pa ] = pb ;
8494 -- n;
8595 }
8696 return n == 1 ;
@@ -98,24 +108,25 @@ class Solution {
98108``` cpp
99109class Solution {
100110public:
101- vector<int > p;
102-
103111 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+ };
106120 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;
110126 --n;
111127 }
112128 return n == 1;
113129 }
114-
115- int find (int x) {
116- if (p[ x] != x) p[ x] = find(p[ x] );
117- return p[ x] ;
118- }
119130};
120131```
121132
@@ -125,19 +136,19 @@ func validTree(n int, edges [][]int) bool {
125136 for i := range p {
126137 p[i] = i
127138 }
128- var find func(x int) int
139+ var find func(int) int
129140 find = func(x int) int {
130141 if p[x] != x {
131142 p[x] = find(p[x])
132143 }
133144 return p[x]
134145 }
135146 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 {
138149 return false
139150 }
140- p[find(a) ] = find(b)
151+ p[pa ] = pb
141152 n--
142153 }
143154 return n == 1
@@ -151,24 +162,170 @@ func validTree(n int, edges [][]int) bool {
151162 * @return {boolean}
152163 */
153164var 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) {
160168 p[x] = find (p[x]);
161169 }
162170 return p[x];
163- }
171+ };
164172 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) {
166176 return false ;
167177 }
168- p[find (a) ] = find (b) ;
178+ p[pa ] = pb ;
169179 -- n;
170180 }
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 ;
172329};
173330```
174331
0 commit comments