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.
这道题主要就是判断1.是否有环路 2. 是否是连通图
可以用DFS, BFS 和 Union find,union find最合适。
对于DFS和BFS,首先都是建立adjacent list,把edges连接的所有情况加入邻接链表,注意需要对称加入,对于[a,b],要对a加入b,对b加入a。都可以用visited来记录是否遍历过。
1. BFS
bfs基本都是用queue实现,首先加入第一个点,每次poll出一个点,对其邻接链表遍历,入队,注意要将该点从其遍历到的邻接链表的点的邻接链表中删去,保证一条边不会来回走两次(为什么前面要对称加入而这里又要删去一边,因为不知道点之间联通的情况是怎么样的,在进行遍历的时候可能是从a->b的方向也可能相反,如果只加一个,在连通图遍历的时候本来连着的边会断掉)。用count记录连入连通图的点的个数,最后和n比。
再次提醒,对于list之类get到的点,都是object,不是int,在赋值给int时要(int),在用remove时,注意remove掉的是object,不能是int,remove(int index),remove(object ob),这两种要区分开,这里是要remove掉这个对象,所以要加(Integer)。
class Solution { public boolean validTree(int n, int[][] edges) { if(n==0) return false; List[] list=new List[n]; for(int i=0;i<n;i++){ list[i]=new ArrayList<Integer>(); } for(int[] pair:edges){ list[pair[0]].add(pair[1]); list[pair[1]].add(pair[0]); } Queue<Integer> queue=new LinkedList<>(); queue.offer(0); boolean[] visited=new boolean[n]; int count=1; while(!queue.isEmpty()){ int a=queue.poll(); if(visited[a]) return false; visited[a]=true; for(int i=0;i<list[a].size();i++){ int m=(int)list[a].get(i);//注意要转int queue.offer(m); count++; list[m].remove((Integer)a);//注意要加(Integer),要不然是被认为是index,删除 } } return count==n; } }
2.DFS
dfs中需要记录pre,来避免a->b->a这样的遍历,从而被当成是环路。
class Solution { public boolean validTree(int n, int[][] edges) { if(n==0) return false; List[] list=new List[n]; for(int i=0;i<n;i++){ list[i]=new ArrayList<Integer>(); } for(int[] pair:edges){ list[pair[0]].add(pair[1]); list[pair[1]].add(pair[0]); } boolean[] visited=new boolean[n]; if(dfs(list, visited, 0,-1)) return false; for(int i=0;i<n;i++){ if(!visited[i]) return false; } return true; } public boolean dfs(List[] list, boolean[] visited, int id, int pre){ if(visited[id]) return true; visited[id]=true; for(int i=0;i<list[id].size();i++){ if(pre==(int)list[id].get(i)) continue; if(dfs(list, visited, (int)list[id].get(i), id)) return true; } return false; } }
3. Union Find
用count记录连通图的个数,每并一次说明少一个分裂块,如果最后变为1,说明全部连通。
class Solution { public boolean validTree(int n, int[][] edges) { int[] connect=new int[n]; if(edges.length!=n-1) return false; for(int i=0;i<n;i++){ connect[i]=i; } int count=n; for(int i=0;i<edges.length;i++){ int a=findroot(connect,edges[i][0]); int b=findroot(connect,edges[i][1]); if(a==b) return false; count--; connect[b]=a; } return count==1; } public int findroot(int[] connect, int id){ while(connect[id]!=id) id=connect[id]; return id; } }