[LeetCode] 261. Graph Valid Tree 图是否是树
Given n
nodes labeled from 0
to n - 1
and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.
For example:
Given n = 5
and edges = [[0, 1], [0, 2], [0, 3], [1, 4]]
, return true
.
Given n = 5
and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]
, return false
.
Hint:
- Given
n = 5
andedges = [[0, 1], [1, 2], [3, 4]]
, what should your return? Is this case a valid tree? - According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.”
Note: you can assume that no duplicate edges will appear in edges
. Since all edges are undirected, [0, 1]
is the same as [1, 0]
and thus will not appear together in edges
.
给一个无向图,判断其是否为一棵树。如果是树的话,所有的节点必须是连接的,也就是说必须是连通图,而且不能有环,所以就变成了验证是否是连通图和是否含有环。
解法1: DFS
解法2: BFS
解法3: Union Find
Java: DFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public boolean validTree( int n, int [][] edges) { HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>(); for ( int i= 0 ; i<n; i++){ ArrayList<Integer> list = new ArrayList<Integer>(); map.put(i, list); } for ( int [] edge: edges){ map.get(edge[ 0 ]).add(edge[ 1 ]); map.get(edge[ 1 ]).add(edge[ 0 ]); } boolean [] visited = new boolean [n]; if (!helper( 0 , - 1 , map, visited)) return false ; for ( boolean b: visited){ if (!b) return false ; } return true ; } public boolean helper( int curr, int parent, HashMap<Integer, ArrayList<Integer>> map, boolean [] visited){ if (visited[curr]) return false ; visited[curr] = true ; for ( int i: map.get(curr)){ if (i!=parent && !helper(i, curr, map, visited)){ return false ; } } return true ; } |
Java: BFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public boolean validTree( int n, int [][] edges) { HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>(); for ( int i= 0 ; i<n; i++){ ArrayList<Integer> list = new ArrayList<Integer>(); map.put(i, list); } for ( int [] edge: edges){ map.get(edge[ 0 ]).add(edge[ 1 ]); map.get(edge[ 1 ]).add(edge[ 0 ]); } boolean [] visited = new boolean [n]; LinkedList<Integer> queue = new LinkedList<Integer>(); queue.offer( 0 ); while (!queue.isEmpty()){ int top = queue.poll(); if (visited[top]) return false ; visited[top]= true ; for ( int i: map.get(top)){ if (!visited[i]) queue.offer(i); } } for ( boolean b: visited){ if (!b) return false ; } return true ; |
Java:BFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | public class Solution { /** * @param n an integer * @param edges a list of undirected edges * @return true if it's a valid tree, or false */ public boolean validTree( int n, int [][] edges) { if (n == 0 ) { return false ; } if (edges.length != n - 1 ) { return false ; } Map<Integer, Set<Integer>> graph = initializeGraph(n, edges); // bfs Queue<Integer> queue = new LinkedList<>(); Set<Integer> hash = new HashSet<>(); queue.offer( 0 ); hash.add( 0 ); while (!queue.isEmpty()) { int node = queue.poll(); for (Integer neighbor : graph.get(node)) { if (hash.contains(neighbor)) { continue ; } hash.add(neighbor); queue.offer(neighbor); } } return (hash.size() == n); } private Map<Integer, Set<Integer>> initializeGraph( int n, int [][] edges) { Map<Integer, Set<Integer>> graph = new HashMap<>(); for ( int i = 0 ; i < n; i++) { graph.put(i, new HashSet<Integer>()); } for ( int i = 0 ; i < edges.length; i++) { int u = edges[i][ 0 ]; int v = edges[i][ 1 ]; graph.get(u).add(v); graph.get(v).add(u); } return graph; } } |
Java: Union Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | public class Solution { class UnionFind{ HashMap<Integer, Integer> father = new HashMap<Integer, Integer>(); UnionFind( int n){ for ( int i = 0 ; i < n; i++) { father.put(i, i); } } int compressed_find( int x){ int parent = father.get(x); while (parent!=father.get(parent)) { parent = father.get(parent); } int temp = - 1 ; int fa = father.get(x); while (fa!=father.get(fa)) { temp = father.get(fa); father.put(fa, parent) ; fa = temp; } return parent; } void union( int x, int y){ int fa_x = compressed_find(x); int fa_y = compressed_find(y); if (fa_x != fa_y) father.put(fa_x, fa_y); } } /** * @param n an integer * @param edges a list of undirected edges * @return true if it's a valid tree, or false */ public boolean validTree( int n, int [][] edges) { // tree should have n nodes with n-1 edges if (n - 1 != edges.length) { return false ; } UnionFind uf = new UnionFind(n); for ( int i = 0 ; i < edges.length; i++) { if (uf.compressed_find(edges[i][ 0 ]) == uf.compressed_find(edges[i][ 1 ])) { return false ; } uf.union(edges[i][ 0 ], edges[i][ 1 ]); } return true ; } } |
Python: DFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class Solution( object ): def validTree( self , n, edges): lookup = collections.defaultdict( list ) for edge in edges: lookup[edge[ 0 ]].append(edge[ 1 ]) lookup[edge[ 1 ]].append(edge[ 0 ]) visited = [ False ] * n if not self .helper( 0 , - 1 , lookup, visited): return False for v in visited: if not v: return False return True def helper( self , curr, parent, lookup, visited): print curr, visited if visited[curr]: return False visited[curr] = True for i in lookup[curr]: if (i ! = parent and not self .helper(i, curr, lookup, visited)): return False return True if __name__ = = '__main__' : print Solution().validTree( 5 , [[ 0 , 1 ], [ 0 , 2 ], [ 0 , 3 ], [ 1 , 4 ]]) print Solution().validTree( 5 , [[ 0 , 1 ], [ 1 , 2 ], [ 2 , 3 ], [ 1 , 3 ], [ 1 , 4 ]]) |
Python: BFS, Time: O(|V| + |E|), Space: O(|V| + |E|)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class Solution( object ): # @param {integer} n # @param {integer[][]} edges # @return {boolean} def validTree( self , n, edges): if len (edges) ! = n - 1 : # Check number of edges. return False # init node's neighbors in dict neighbors = collections.defaultdict( list ) for u, v in edges: neighbors[u].append(v) neighbors[v].append(u) # BFS to check whether the graph is valid tree. visited = {} q = collections.deque([ 0 ]) while q: curr = q.popleft() visited[curr] = True for node in neighbors[curr]: if node not in visited: visited[node] = True q.append(node) return len (visited) = = n |
Python: Union Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Solution: # @param {int} n an integer # @param {int[][]} edges a list of undirected edges # @return {boolean} true if it's a valid tree, or false def validTree( self , n, edges): # Write your code here root = [i for i in range (n)] for i in edges: root1 = self .find(root, i[ 0 ]) root2 = self .find(root, i[ 1 ]) if root1 = = root2: return False else : root[root1] = root2 return len (edges) = = n - 1 def find( self , root, e): if root[e] = = e: return e else : root[e] = self .find(root, root[e]) return root[e] |
C++: DFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class Solution { public : bool validTree( int n, vector<pair< int , int >>& edges) { vector<vector< int >> g(n, vector< int >()); vector< bool > v(n, false ); for ( auto a : edges) { g[a.first].push_back(a.second); g[a.second].push_back(a.first); } if (!dfs(g, v, 0, -1)) return false ; for ( auto a : v) { if (!a) return false ; } return true ; } bool dfs(vector<vector< int >> &g, vector< bool > &v, int cur, int pre) { if (v[cur]) return false ; v[cur] = true ; for ( auto a : g[cur]) { if (a != pre) { if (!dfs(g, v, a, cur)) return false ; } } return true ; } }; |
C++: BFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Solution { public : bool validTree( int n, vector<pair< int , int >>& edges) { vector<unordered_set< int >> g(n, unordered_set< int >()); unordered_set< int > s{{0}}; queue< int > q{{0}}; for ( auto a : edges) { g[a.first].insert(a.second); g[a.second].insert(a.first); } while (!q.empty()) { int t = q.front(); q.pop(); for ( auto a : g[t]) { if (s.count(a)) return false ; s.insert(a); q.push(a); g[a].erase(t); } } return s.size() == n; } }; |
C++: Union Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Solution { public : bool validTree( int n, vector<pair< int , int >>& edges) { vector< int > roots(n, -1); for ( auto a : edges) { int x = find(roots, a.first), y = find(roots, a.second); if (x == y) return false ; roots[x] = y; } return edges.size() == n - 1; } int find(vector< int > &roots, int i) { while (roots[i] != -1) i = roots[i]; return i; } }; |
类似题目:
[LeetCode] 200. Number of Islands 岛屿的数量
[LeetCode] 305. Number of Islands II 岛屿的数量之二
[LeetCode] 323. Number of Connected Components in an Undirected Graph 无向图中的连通区域的个数
All LeetCode Questions List 题目汇总
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架