题目描述:
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
.
Note: 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 in edges
.
解题思路:
判断给出的点和边构成的图是否为一个树,可以认为是判断图中有无环的存在,可以使用并查集(union find)来进行解答。
本题中的图为无向图, 即[0,1]和[1,0]为同一条边,为了方便寻找唯一根结点,在union的过程中,将值较大的父亲值设置为值较小的父亲,即:
if(a < b) parent[rootB] = rootA; else parent[rootA] = rootB;
我遇见的bug:
- 边界问题检测:题目要求为能否构成一棵有效的树,若边集为空,有以下情况:
- 只有一个节点:可以构成一棵有效的树
- 有一个以上的节点:因为没有边。所以存在离散的节点,所以不能构成一棵有效的树
- 没有节点:空树
- 如果存在n个节点,若要把n个节点连接起来,至少需要n-1条边。若边的条数少于n-1,则无法链接所有节点,不能构成一颗有效的树
public class Solution { /** * @param n: An integer * @param edges: a list of undirected edges * @return: true if it's a valid tree, or false */ public boolean validTree(int n, int[][] edges) { // write your code here if(edges.length == 0 && n > 1) return false; if(n == 0 || (edges.length == 0 && n == 1)) return true; if(edges.length < n-1) return false; int[] parent = new int[n]; for(int i = 0; i < n; i++){ parent[i] = i; } for(int i = 0; i < edges.length; i++){ if(!union(parent, edges[i][0], edges[i][1])) return false; } int root = find(parent, 0); for(int i = 0; i < n; i++){ if(find(parent, i) != root) return false; } return true; } private int find(int[] parent, int a){ if(parent[a] == a) return a; return parent[a] = find(parent, parent[a]); } private boolean union(int[] parent, int a, int b){ int rootA = find(parent, a); int rootB = find(parent, b); if(rootA != rootB){ if(a < b) parent[rootB] = rootA; else parent[rootA] = rootB; return true; } return false; } }
突然想到:
当边数等于n-1时,可能出现一棵有效的树,此时无环,若存在环,则一定有孤立的点。
当边数大于n-1时,一定有环出现。
所以上面代码应该可以更简洁一点?