Given
n
nodes labeled from0
ton - 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.nodeFor example:app
Given
n = 5
andedges = [[0, 1], [0, 2], [0, 3], [1, 4]]
, returntrue
.spaGiven
n = 5
andedges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]
, returnfalse
.codeNote: 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 inedges
.排序
這種驗證有效的圖都是一類題。無非就是幾種方法,好比DFS。注意樹有個特徵就是一個child不能有兩個parent, 根平時拓撲排序找環的的差異,固然因爲這道題是無向圖,不用考慮這方面。這題有幾個要注意的地方,好比一個樹只能有一個root,若是這個樹存在多個root, 那確定無效。get
因爲這道題是無向圖,那麼咱們其實能夠從任意一個點開始DFS,不用必須從root,由於無向圖從任意一點均可以遍歷到整塊部分。添加edge的時候兩個方向都添就能夠了,另外就是還有個注意的地方就是若是在遍歷neighbors的時候,本身parent不要遍歷,不然直接返回false覺得有環了。總結一句就是,這種無向圖每一個點遍歷一次就能夠了,不然就意味着有環。it
若是這道題換成是有向圖的話,解法見下文。io
time: O(V + E), space: O(h)function
public class Solution { public boolean validTree(int n, int[][] edges) { List<Integer>[] graph = new List[n]; for (int i = 0; i < n; i++) { graph[i] = new ArrayList<Integer>(); } for (int i = 0; i < edges.length; i++) { graph[edges[i][0]].add(edges[i][1]); graph[edges[i][1]].add(edges[i][0]); } boolean[] visited = new boolean[n]; if (!dfs(graph, 0, visited, -1)) { return false; } // 檢測是否存在多個root, 如是意味着圖無效 for (int i = 0; i < n; i++) { if (!visited[i]) { return false; } } return true; } private boolean dfs(List<Integer>[] graph, int i, boolean[] visited, int prev) { // 發現環 if (visited[i]) { return false; } visited[i] = true; for (int num : graph[i]) { if (prev != num && !dfs(graph, num, visited, i)) { return false; } } return true; } }
Given
n
nodes labeled from0
ton - 1
and a list of directed edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.classFor example:
Given
n = 5
andedges = [[0, 1], [0, 2], [0, 3], [1, 4]]
, returntrue
.Given
n = 5
andedges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]
, returnfalse
.
Givenn = 5
andedges = [[0, 1], [1, 2], [3, 4]]
, returnfalse
.
有向圖要注意的地方不只是不能有多個root存在,與上題不一樣的是須要從root開始遍歷才能慢慢遍歷到整個圖,其餘方面基本跟上題同樣,遍歷過程當中一個點只能visit一次,不然便是那種一個child多個parent狀況。
time: O(V+E), space: O(h)
public class Solution { public boolean validTree(int n, int[][] edges) { List<Integer>[] graph = new List[n]; Set<Integer> inDegree = new HashSet<>(); for (int i = 0; i < n; i++) { graph[i] = new ArrayList<Integer>(); } for (int i = 0; i < edges.length; i++) { graph[edges[i][0]].add(edges[i][1]); inDegree.add(edges[i][1]); } int root = 0; int count = 0; for (int i = 0; i < n; i++) { if (!inDegree.contains(i)) { root = i; count++; } } if (count != 1) return false; boolean[] visited = new boolean[n]; if (!dfs(graph, root, visited)) { return false; } return true; } private boolean dfs(List<Integer>[] graph, int i, boolean[] visited) { // 發現環或一child多個parents if (visited[i]) { return false; } visited[i] = true; for (int num : graph[i]) { if (!dfs(graph, num, visited)) { return false; } } return true; } }