[LeetCode] 261. Graph Valid Tree
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 <= 2000
0 <= edges.length <= 5000
edges[i].length == 2
0 <= ai, bi < n
ai != bi
- There are no self-loops or repeated edges.
以图判树。
给定从
0
到n-1
标号的n
个结点,和一个无向边列表(每条边以结点对来表示),请编写一个函数用来判断这些边是否能够形成一个合法有效的树结构。注意:你可以假定边列表 edges 中不会出现重复的边。由于所有的边是无向边,边 [0,1] 和边 [1,0] 是相同的,因此不会同时出现在边列表 edges 中。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/graph-valid-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这道题属于图和树的综合题。给的 input 是节点的个数 n 和一些边 edges,请你判断能否组成一棵树。有一个概念需要复习,树和图的区别在于图是可以有环 (cycle) 的,树不能有环;同时图的节点有可能不会连在一片,但是树的所有节点必定都是相连成一片的。对于这道题,有一些 corner case 需要特判,如果只有一个节点的话,那么就一定没有 edges;因为题设说了不会给额外的边,所以如果边的数量 != 节点数量 - 1的话,一定不是树。
照着这个思路,我还是提供三种做法,BFS, DFS 和 Union Find。三种做法的时间空间复杂度都一样,union find 在运行时间上可以通过路径压缩变得更快。判断的逻辑是如果反复遇到某个节点或者最终有某个节点没有访问过,就说明有环或者是图(比如有超过一组联通的点)
BFS
时间O(V * E)
空间O(n)
Java实现
1 class Solution { 2 public boolean validTree(int n, int[][] edges) { 3 // create graph 4 List<List<Integer>> graph = new ArrayList<>(); 5 for (int i = 0; i < n; i++) { 6 graph.add(new ArrayList<>()); 7 } 8 for (int i = 0; i < edges.length; i++) { 9 graph.get(edges[i][0]).add(edges[i][1]); 10 graph.get(edges[i][1]).add(edges[i][0]); 11 } 12 13 boolean[] visited = new boolean[n]; 14 Queue<Integer> queue = new LinkedList<>(); 15 queue.offer(0); 16 while (!queue.isEmpty()) { 17 int cur = queue.poll(); 18 if (visited[cur] == true) { 19 return false; 20 } 21 visited[cur] = true; 22 for (int nei : graph.get(cur)) { 23 if (!visited[nei]) { 24 queue.offer(nei); 25 } 26 } 27 } 28 29 for (int i = 0; i < n; i++) { 30 if (visited[i] == false) { 31 return false; 32 } 33 } 34 return true; 35 } 36 }
DFS
时间O(V * E)
空间O(n)
Java实现
1 class Solution { 2 public boolean validTree(int n, int[][] edges) { 3 // create graph 4 List<List<Integer>> g = new ArrayList<>(); 5 for (int i = 0; i < n; i++) { 6 g.add(new ArrayList<>()); 7 } 8 for (int[] e : edges) { 9 g.get(e[0]).add(e[1]); 10 g.get(e[1]).add(e[0]); 11 } 12 13 HashSet<Integer> visited = new HashSet<>(); 14 visited.add(0); 15 boolean res = helper(g, visited, 0, -1); 16 if (res == false) { 17 return false; 18 } 19 return visited.size() == n ? true : false; 20 } 21 22 private boolean helper(List<List<Integer>> g, HashSet<Integer> visited, int cur, int parent) { 23 List<Integer> neighbors = g.get(cur); 24 for (int nei : neighbors) { 25 if (nei == parent) { 26 continue; 27 } 28 // cycle 29 if (visited.contains(nei)) { 30 return false; 31 } 32 visited.add(nei); 33 boolean res = helper(g, visited, nei, cur); 34 if (res == false) { 35 return false; 36 } 37 } 38 return true; 39 } 40 }
Union Find
时间O(V * E)
空间O(n)
Java实现
1 class Solution { 2 public boolean validTree(int n, int[][] edges) { 3 // corner case 4 if (n == 1 && edges.length == 0) { 5 return true; 6 } 7 if (n < 1 || edges == null || edges.length != n - 1) { 8 return false; 9 } 10 11 // normal case 12 int[] roots = new int[n]; 13 for (int i = 0; i < n; i++) { 14 roots[i] = -1; 15 } 16 17 for (int[] pair : edges) { 18 int x = find(roots, pair[0]); 19 int y = find(roots, pair[1]); 20 if (x == y) { 21 return false; 22 } 23 roots[x] = y; 24 } 25 return true; 26 } 27 28 private int find(int[] roots, int i) { 29 while (roots[i] != -1) { 30 i = roots[i]; 31 } 32 return i; 33 } 34 }
相关题目