[Leetcode] Graph Valid Tree 判斷一個圖是否爲樹

Graph Valid Tree

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.html

For example:java

Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true.node

Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]],
return false.數據結構

Hint:app

Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], what should your return? Is this case a valid tree? Show More Hint 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.oop

並查集法

複雜度

O( V + E ) 時間 O(V) 空間 ui

並查集(帶路徑壓縮path compression)兩個操做的平攤時間(amortized time)複雜度爲O(log*n),讀做log星n,它增加得極爲緩慢,因此認爲O(1)this

思路

感性的認識一下無向圖中樹的樣子:假設是連通圖,圖若是是樹,那麼樹是無根樹,即誰都是根,因此無根。
這個樹和樹這個數據結構(好比二叉樹)還不同,二叉樹是一個有根樹,有個特殊節點叫根。.net

這道題裏的樹,就是任意兩點有且只有一條路徑可達,這條路徑的每一個邊只走一次。
換句話講,圖想要是樹,得是沒有迴路的連通圖,就是要知足兩個性質:code

  1. 是連通圖

  2. 無環

通常來說判斷是否有環都在一個連通圖上判斷,若是這個圖有多個連通份量,那就要對每一個連通份量都判斷一下是否有環。都沒有環,那就是森林。只有一個連通份量尚未環,就是樹,無根樹。

無向圖邊的兩端是對稱的,無向圖講究連通這個概念,沒有方向,沒有拓撲,很像集合,因此很是適合用並查集來解決。
解決的方法:
想象一開始這個圖只有頂點,沒有邊,咱們來一條一條的添加邊。
每遇到一條邊,判斷這邊的兩個端點是否在同一個集合裏?集合的property:表示一個連通份量,裏面的任意兩點有且只有一條路徑可達

  • 在的話,表示有環:由於兩個點在一個集合裏就表示這兩個點已經有一條路徑了,如今再加一條路徑,必然構成環。

  • 不在的話,表示不構成環,咱們應該合併這兩個集合:由於加上這條邊,兩個集合就被連起來了,合併成了一個集合

注意

若是想要複雜度爲O(V+E),必須用路徑壓縮。
並查集寫法參考
注意union(p,q)方法:用find()找p,q的老大哥,合併的是p,q的老大哥。

代碼

UnionFind Utility(很是intuitive,應該練習在5分鐘內寫完):

class UnionFind {
    private int[] father;
    private int count;
    public UnionFind(int n) {
        father = new int[n];
        count = n;
        for (int i = 0; i < n; i++){
            father[i] = i;
        }
    }
    public int count() {
        return this.count;
    }
    public int find(int p) {
        int root = father[p];
        while (root != father[root])
            root = father[root];
        //as long as we get here, root is the final dad
        while (p != root) {
            int tmp = father[p];
            father[p] = root;
            p = tmp;
        }
        return root;
    }
    public void union(int p, int q) {
        int fatherP = find(p);
        int fatherQ = find(q);
        if (fatherP != fatherQ) {
            father[fatherP] = fatherQ;
            count--;
        }
    }
}

主程序

public class Solution {
    public boolean validTree(int n, int[][] edges) {
        UnionFind uf = new UnionFind(n);
        for (int[] edge : edges){
            int p = edge[0];
            int q = edge[1];
            if (uf.find(p) == uf.find(q))
                return false;
            else
                uf.union(p,q);
        }
        return uf.count() == 1;
    }
}

DFS/BFS法

複雜度

O( V + E ) 時間 O(V) 空間

思路

無向圖找環和有向圖找環本質上徹底不一樣。
有向圖找環須要三種顏色。
無向圖找環只須要兩種顏色,就是訪問過的和沒訪問的。

dfs過程當中若是碰到訪問過的節點(固然這個節點不能是來時的節點),就是有環。

注意

Integer的比較問題

代碼

public class Solution {
    public boolean validTree(int n, int[][] edges) {
        HashSet<Integer> visited = new HashSet<Integer>();
        List<List<Integer>> adjList = new ArrayList<List<Integer>>();
        for (int i=0; i<n; ++i)  
            adjList.add(new ArrayList<Integer>()); 
        for (int[] edge: edges) {
            adjList.get(edge[0]).add(edge[1]);
            adjList.get(edge[1]).add(edge[0]);
        }
        if (hasCycle(-1, 0, visited, adjList))  // has cycle?
            return false;   
        if (visited.size() != n) // is all connected?
            return false;   
        return true;
    }

    private boolean hasCycle(Integer pred, Integer vertex, HashSet<Integer> visited, List<List<Integer>> adjList) {
        visited.add(vertex);  // current vertex is being visited
        for (Integer succ: adjList.get(vertex)) {  // successors of current vertex
            if (!succ.equals(pred)) {  // exclude current vertex's predecessor
                if (visited.contains(succ)) { 
                    return true; // back edge/loop detected!
                }  
                else  {
                    if (hasCycle(vertex, succ, visited, adjList)) { 
                        return true; 
                    }
                }
            }
        }
        return false;
    }
}
相關文章
相關標籤/搜索