Graph Valid Tree
- Median
- keyword: Data structure, Graph, Union-Find, dummy node
- 类似: Graph, missing range
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:
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
idea:
- 其实hint已经说完了解法: 即
Connected Compoennt 和 hasCycle
. 即先判断是否有环, 并且每个点都能reachable. 之前做alien dictionary的时候也有hasCycle的判断. 这里我使用Algs4里面的经典写法: DFS. 其中判断: `如果某个node的adj已经visit过, 并且该adj不是parent(*)的话, 则说明是cycle了.
- 注意这里有个catch: 并不是recursion call都要return, 而是true的话直接return, false的话还要接着walk down the tree!
代码如下
public boolean hasCycle(List<List<Integer>> G, int u, boolean[] visited, int parent) { visited[u] = true; for (int v : G.adj(u)) { if (!visited(v)) { if (hasCycle(G, v, visited, u) == true) { return true; // catch. 只有发现cycle了才要return, 否则继续搜索. } } else { if (v != parent) { return true; } } } return false; }
algs4里面是对每一个node进行一次hasCycle判断. 而这里并不需要, 因为这里的node确定了: 是
0~n-1
的数. 而且要保证所有点都连起来. 于是可以对0求cycle即可. 那么0的parent是谁呢? 我一开始并不知道啊?!?!- 这里再次体现了构造的重要性: 可以看看missing range的
low-1/upper+1
hasCycle(G, 0, visited, 0);
: algs4hasCycle(G, 0, visited, -1);
: discuss
- 这里再次体现了构造的重要性: 可以看看missing range的
代码如下
public boolean validTree(int n, int[][] edges) {
List<List<Integer>> G = new ArrayList<>();
return dfs(n, edges, G);
}
public boolean dfs(int n, int[][] edges, List<List<Integer>> G) {
for (int i = 0; i < n; ++i) {
G.add(i, new ArrayList<>());
}
for (int i = 0; i < edges.length; ++i) {
int u = edges[i][0], v = edges[i][1];
G.get(u).add(v);
G.get(v).add(u);
}
boolean[] visited = new boolean[n];
if (hasCycle(G, 0, visited, 0)) { // parent是0/-1都可以. 为什么呢?
return false;
}
for (int i = 0; i < n; ++i) {
if (visited[i] != true) {
return false;
}
}
return true;
}