Welcome to Subscribe On Youtube
261. Graph Valid Tree
Description
You have a graph of n nodes labeled from 0 to n - 1. You are given an integer n and a list of edges where edges[i] = [ai, bi] indicates that there is an undirected edge between nodes ai and bi in the graph.
Return true if the edges of the given graph make up a valid tree, and false otherwise.
Example 1:

Input: n = 5, edges = [[0,1],[0,2],[0,3],[1,4]] Output: true
Example 2:

Input: n = 5, edges = [[0,1],[1,2],[2,3],[1,3],[1,4]] Output: false
Constraints:
1 <= n <= 20000 <= edges.length <= 5000edges[i].length == 20 <= ai, bi < nai != bi- There are no self-loops or repeated edges.
Solutions
Solution 1
Union find.
Solution 2: DFS
We can also use depth-first search to determine whether there is a cycle. We can use an array $vis$ to record the visited nodes. During the search, we first mark the node as visited, then traverse the nodes adjacent to this node. If the adjacent node has been visited, we skip it, otherwise we recursively visit the adjacent node. Finally, we check whether all nodes have been visited. If there are nodes that have not been visited, it means that it cannot form a tree, so we return false.
The time complexity is $O(n)$, and the space complexity is $O(n)$, where $n$ is the number of nodes.
-
class Solution { private int[] p; public boolean validTree(int n, int[][] edges) { p = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; } for (int[] e : edges) { int a = e[0], b = e[1]; if (find(a) == find(b)) { return false; } p[find(a)] = find(b); --n; } return n == 1; } private int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } } // Solution 2 class Solution { private List<Integer>[] g; private Set<Integer> vis = new HashSet<>(); public boolean validTree(int n, int[][] edges) { if (edges.length != n - 1) { return false; } g = new List[n]; Arrays.setAll(g, k -> new ArrayList<>()); for (var e : edges) { int a = e[0], b = e[1]; g[a].add(b); g[b].add(a); } dfs(0); return vis.size() == n; } private void dfs(int i) { vis.add(i); for (int j : g[i]) { if (!vis.contains(j)) { dfs(j); } } } } -
class Solution { public: vector<int> p; bool validTree(int n, vector<vector<int>>& edges) { p.resize(n); for (int i = 0; i < n; ++i) p[i] = i; for (auto& e : edges) { int a = e[0], b = e[1]; if (find(a) == find(b)) return 0; p[find(a)] = find(b); --n; } return n == 1; } int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } }; // Solution 2 class Solution { public: bool validTree(int n, vector<vector<int>>& edges) { if (edges.size() != n - 1) { return false; } vector<int> g[n]; vector<int> vis(n); function<void(int)> dfs = [&](int i) { vis[i] = true; --n; for (int j : g[i]) { if (!vis[j]) { dfs(j); } } }; for (auto& e : edges) { int a = e[0], b = e[1]; g[a].push_back(b); g[b].push_back(a); } dfs(0); return n == 0; } }; -
class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool: def find(x): if p[x] != x: p[x] = find(p[x]) return p[x] p = list(range(n)) for a, b in edges: if find(a) == find(b): return False p[find(a)] = find(b) n -= 1 return n == 1 # Solution 2 class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool: def dfs(i: int): vis.add(i) for j in g[i]: if j not in vis: dfs(j) if len(edges) != n - 1: return False g = [[] for _ in range(n)] for a, b in edges: g[a].append(b) g[b].append(a) vis = set() dfs(0) return len(vis) == n -
func validTree(n int, edges [][]int) bool { p := make([]int, n) for i := range p { p[i] = i } var find func(x int) int find = func(x int) int { if p[x] != x { p[x] = find(p[x]) } return p[x] } for _, e := range edges { a, b := e[0], e[1] if find(a) == find(b) { return false } p[find(a)] = find(b) n-- } return n == 1 } // Solution 2 func validTree(n int, edges [][]int) bool { if len(edges) != n-1 { return false } g := make([][]int, n) vis := make([]bool, n) for _, e := range edges { a, b := e[0], e[1] g[a] = append(g[a], b) g[b] = append(g[b], a) } var dfs func(int) dfs = func(i int) { vis[i] = true n-- for _, j := range g[i] { if !vis[j] { dfs(j) } } } dfs(0) return n == 0 } -
/** * @param {number} n * @param {number[][]} edges * @return {boolean} */ var validTree = function (n, edges) { let p = new Array(n); for (let i = 0; i < n; ++i) { p[i] = i; } function find(x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } for (const [a, b] of edges) { if (find(a) == find(b)) { return false; } p[find(a)] = find(b); --n; } return n == 1; }; // Solution 2 /** * @param {number} n * @param {number[][]} edges * @return {boolean} */ var validTree = function (n, edges) { if (edges.length !== n - 1) { return false; } const g = Array.from({ length: n }, () => []); const vis = Array.from({ length: n }, () => false); for (const [a, b] of edges) { g[a].push(b); g[b].push(a); } const dfs = i => { vis[i] = true; --n; for (const j of g[i]) { if (!vis[j]) { dfs(j); } } }; dfs(0); return n === 0; };