Graph Valid Tree
A tree is just a connected graph with exactly `n - 1` edges, so the edge count is checked first as a fast fail — it catches both 'too few edges to reach everything' and 'an extra edge means a cycle somewhere' — before a single stack DFS from node `0` confirms the rest is actually connected.
The problem
Implement `validTree(n, edges)` for `n` nodes labelled `0` to `n - 1` and a list of undirected edges. Return whether the edges form a valid tree — every node connected, with no cycles.
`n = 5, edges = [[0,1],[0,2],[0,3],[1,4]]` is a valid tree (`true`). `n = 5, edges = [[0,1],[1,2],[2,3],[1,3],[1,4]]` has a cycle (`1`-`2`-`3`-`1`), so it's `false`.
The approach
A tree on `n` nodes has exactly `n - 1` edges — no more, no fewer. That single arithmetic check does double duty: fewer edges can't possibly reach every node, and any extra edge beyond `n - 1` has to close a cycle somewhere. It's a fast fail before any traversal runs.
Once the edge count passes, the only remaining question is connectivity: build the same array-indexed adjacency list as `countComponents`, then run one stack DFS from node `0` and check whether `visited` ends up covering all `n` nodes.
Correctness relies on the two checks together, not either alone — `edges.length === n - 1` by itself doesn't rule out a disconnected graph that happens to have a cycle elsewhere, and a connectivity check alone doesn't rule out an extra edge creating a cycle. Combined, they pin down exactly one shape: a connected acyclic graph.
The solution
class Solution {
/**
* @param {number} n
* @param {number[][]} edges
* @returns {boolean}
*/
validTree(n, edges) {
if (edges.length !== n - 1) return false;
const graph = Array.from({ length: n }, () => []);
for (const [e1, e2] of edges) {
graph[e1].push(e2);
graph[e2].push(e1);
}
const visited = new Set();
visited.add(0);
const stack = [0];
while (stack.length) {
const node = stack.pop();
for (const neighbour of graph[node]) {
if (!visited.has(neighbour)) {
visited.add(neighbour);
stack.push(neighbour);
}
}
}
return visited.size === n;
}
}Time O(V + E)Space O(V)