[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.node

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

Hint:this

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

並查集

複雜度

時間 O(N^M) 空間 O(1)code

思路

判斷輸入的邊是否能構成一個樹,咱們須要肯定兩件事:blog

  1. 這些邊是否構成環路,若是有環則不能構成樹接口

  2. 這些邊是否能將全部節點連通,若是有不能連通的節點則不能構成樹get

由於不須要知道具體的樹長什麼樣子,只要知道連通的關係,因此並查集相比深度優先搜索是更好的方法。咱們定義一個並查集的數據結構,並提供標準的四個接口:

  • union 將兩個節點放入一個集合中

  • find 找到該節點所屬的集合編號

  • areConnected 判斷兩個節點是不是一個集合

  • count 返回該並查集中有多少個獨立的集合

具體並查集的原理,參見這篇文章。簡單來說,就是先構建一個數組,節點0到節點n-1,剛開始都各自獨立的屬於本身的集合。這時集合的編號是節點號。而後,每次union操做時,咱們把整個並查集中,全部和第一個節點所屬集合號相同的節點的集合號,都改爲第二個節點的集合號。這樣就將一個集合的節點歸屬到同一個集合號下了。咱們遍歷一遍輸入,把全部邊加入咱們的並查集中,加的同時判斷是否有環路。最後若是並查集中只有一個集合,則說明能夠構建樹。

注意

由於要判斷是否會產生環路,union方法要返回一個boolean,若是兩個節點原本就在一個集合中,就返回假,說明有環路

代碼

public class Solution {
    public boolean validTree(int n, int[][] edges) {
        UnionFind uf = new UnionFind(n);
        for(int i = 0; i < edges.length; i++){
            // 若是兩個節點已經在同一集合中,說明新的邊將產生環路
            if(!uf.union(edges[i][0], edges[i][1])){
                return false;
            }
        }
        return uf.count() == 1;
    }
    
    public class UnionFind {
        
        int[] ids;
        int cnt;
        
        public UnionFind(int size){
            this.ids = new int[size];
            //初始化並查集,每一個節點對應本身的集合號
            for(int i = 0; i < this.ids.length; i++){
                this.ids[i] = i;
            }
            this.cnt = size;
        }
        public boolean union(int m, int n){
            int src = find(m);
            int dst = find(n);
            //若是兩個節點不在同一集合中,將兩個集合合併爲一個
            if(src != dst){
                for(int i = 0; i < ids.length; i++){
                    if(ids[i] == src){
                        ids[i] = dst;
                    }
                }
                // 合併完集合後,集合數減一
                cnt--;
                return true;
            } else {
                return false;
            }
        }
        public int find(int m){
            return ids[m];
        }
        public boolean areConnected(int m, int n){
            return find(m) == find(n);
        }
        public int count(){
            return cnt;
        }
    }
}
相關文章
相關標籤/搜索