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;
    }
}

 

posted on 2018-10-01 13:27  elsie12  阅读(131)  评论(0编辑  收藏  举报