[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:app

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

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

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.排序

分析

這種驗證有效的圖都是一類題。無非就是幾種方法,好比DFS。注意樹有個特徵就是一個child不能有兩個parent, 根平時拓撲排序找環的的差異,固然因爲這道題是無向圖,不用考慮這方面。這題有幾個要注意的地方,好比一個樹只能有一個root,若是這個樹存在多個root, 那確定無效。get

因爲這道題是無向圖,那麼咱們其實能夠從任意一個點開始DFS,不用必須從root,由於無向圖從任意一點均可以遍歷到整塊部分。添加edge的時候兩個方向都添就能夠了,另外就是還有個注意的地方就是若是在遍歷neighbors的時候,本身parent不要遍歷,不然直接返回false覺得有環了。總結一句就是,這種無向圖每一個點遍歷一次就能夠了,不然就意味着有環。it

若是這道題換成是有向圖的話,解法見下文。io

複雜度

time: O(V + E), space: O(h)function

代碼

public class Solution {
     public boolean validTree(int n, int[][] edges) {
        List<Integer>[] graph = new List[n];

        for (int i = 0; i < n; i++) {
            graph[i] = new ArrayList<Integer>();
        }

        for (int i = 0; i < edges.length; i++) {
            graph[edges[i][0]].add(edges[i][1]);
            graph[edges[i][1]].add(edges[i][0]);
        }

        boolean[] visited = new boolean[n];
        if (!dfs(graph, 0, visited, -1)) {
            return false;
        }
        
        // 檢測是否存在多個root, 如是意味着圖無效
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                return false;
            }
        }

        return true;
    }

    private boolean dfs(List<Integer>[] graph, int i, boolean[] visited, int prev) {
        // 發現環
        if (visited[i]) {
            return false;
        }
        visited[i] = true;

        for (int num : graph[i]) {
            if (prev != num && !dfs(graph, num, visited, i)) {
                return false;
            }
        }

        return true;
    }
}

Graph Valid Tree(Directed Edges)

Given n nodes labeled from 0 to n - 1 and a list of directed edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.class

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.
Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], return false.

分析

有向圖要注意的地方不只是不能有多個root存在,與上題不一樣的是須要從root開始遍歷才能慢慢遍歷到整個圖,其餘方面基本跟上題同樣,遍歷過程當中一個點只能visit一次,不然便是那種一個child多個parent狀況。

複雜度

time: O(V+E), space: O(h)

代碼

public class Solution {
    public boolean validTree(int n, int[][] edges) {
        List<Integer>[] graph = new List[n];
        Set<Integer> inDegree = new HashSet<>();

        for (int i = 0; i < n; i++) {
            graph[i] = new ArrayList<Integer>();
        }

        for (int i = 0; i < edges.length; i++) {
            graph[edges[i][0]].add(edges[i][1]);
            inDegree.add(edges[i][1]);
        }

        int root = 0;
        int count = 0;
        for (int i = 0; i < n; i++) {
            if (!inDegree.contains(i)) {
                root = i;
                count++;
            }
        }

        if (count != 1)
            return false;

        boolean[] visited = new boolean[n];
        if (!dfs(graph, root, visited)) {
            return false;
        }

        return true;
    }

    private boolean dfs(List<Integer>[] graph, int i, boolean[] visited) {
        
        // 發現環或一child多個parents
        if (visited[i]) {
            return false;
        }
        visited[i] = true;

        for (int num : graph[i]) {
            if (!dfs(graph, num, visited)) {
                return false;
            }
        }

        return true;
    }          
}
相關文章
相關標籤/搜索