zoukankan      html  css  js  c++  java
  • [LintCode] 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.

    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.

    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.

    Algorithm:

    For an undirected graph of n vertices, if the number of edges is not n - 1, then this graph can not be a valid tree. This graph is either cyclic in the case of more than n - 1 edges, or disconnected in the case of fewer than n - 1 edges. If there are n - 1 edges, then further check is needed to detect if there is any cycle in the graph. If there is a cycle, then this graph is not a valid tree. If there is no cycles, then it is a valid tree.

    Solution 1. BFS, O(V + E) runtime, O(V + E) space 

    Start from a random node and do a BFS, if all vertices can be reached then we know there can not be any cycles, we have a valid tree.

     1 public class Solution {
     2     public boolean validTree(int n, int[][] edges) {
     3         if(edges.length != n - 1)
     4         {
     5             return false;
     6         }
     7         HashMap<Integer, HashSet<Integer>> graph = initializeGraph(n, edges);
     8         
     9         //bfs
    10         Queue<Integer> queue = new LinkedList<Integer>();
    11         HashSet<Integer> visitedSet = new HashSet<Integer>();
    12         
    13         queue.offer(0);
    14         visitedSet.add(0);
    15         int visitedNodes = 0;
    16         while(!queue.isEmpty())
    17         {
    18             int node = queue.poll();
    19             visitedNodes++;
    20             for(Integer neighbor : graph.get(node))
    21             {
    22                 if(visitedSet.contains(neighbor))
    23                 {
    24                     continue;
    25                 }
    26                 visitedSet.add(neighbor);
    27                 queue.offer(neighbor);
    28             }
    29         }
    30         return visitedNodes == n;
    31     }
    32 }

    Solution 2. DFS to count all reachable nodes, O(V + E) runtime, O(V + E) space for graph representation, O(n) for the set of visited nodes. The recursion stack space usage should be taken into account too.

     1 public class Solution {
     2     public boolean validTree(int n, int[][] edges) {
     3         if(edges.length != n - 1)
     4         {
     5             return false;
     6         }
     7         HashMap<Integer, HashSet<Integer>> graph = initializeGraph(n, edges);
     8         HashSet<Integer> visited = new HashSet<Integer>();
     9         visited.add(0);
    10         dfs(0, graph, visited);
    11         return visited.size() == n;   
    12     }
    13     private HashMap<Integer, HashSet<Integer>> initializeGraph(int n, int[][] edges)
    14     {
    15         HashMap<Integer, HashSet<Integer>> graph = new HashMap<Integer, HashSet<Integer>>();
    16         for(int i = 0; i < n; i++)
    17         {
    18             graph.put(i, new HashSet<Integer>());
    19         }
    20         for(int i = 0; i < edges.length; i++)
    21         {
    22             int u = edges[i][0];
    23             int v = edges[i][1];
    24             graph.get(u).add(v);
    25             graph.get(v).add(u);
    26         }
    27         return graph;
    28     }
    29     private void dfs(int startNode, 
    30                     HashMap<Integer, HashSet<Integer>> graph,
    31                     HashSet<Integer> visited){
    32         for(Integer neighbor : graph.get(startNode)){
    33             if(!visited.contains(neighbor)){
    34                 visited.add(neighbor);
    35                 dfs(neighbor, graph, visited);
    36             }
    37         }        
    38     }
    39 }

    Solution 3. DFS to check if there is any cycle

     1 //Algorithm 3. dfs all nodes to check if there is a cycle in this graph. 
     2 //O(m + n) time, O(m + n) space, if not considering the recursion space usage
     3 public class Solution {
     4     public boolean validTree(int n, int[][] edges) {
     5         if(n == 0 || edges.length != n - 1)
     6         {
     7             return false;
     8         }
     9         HashMap<Integer, HashSet<Integer>> graph = initializeGraph(n, edges);
    10         return hasCycleDFS(graph) == false;
    11     }
    12     private HashMap<Integer, HashSet<Integer>> initializeGraph(int n, int[][] edges)
    13     {
    14         HashMap<Integer, HashSet<Integer>> graph = new HashMap<Integer, HashSet<Integer>>();
    15         for(int i = 0; i < n; i++)
    16         {
    17             graph.put(i, new HashSet<Integer>());
    18         }
    19         for(int i = 0; i < edges.length; i++)
    20         {
    21             int u = edges[i][0];
    22             int v = edges[i][1];
    23             graph.get(u).add(v);
    24             graph.get(v).add(u);
    25         }
    26         return graph;
    27     }
    28     private boolean hasCycleDFS(HashMap<Integer, HashSet<Integer>> graph){
    29         HashSet<Integer> visited = new HashSet<Integer>();
    30         for(Integer node : graph.keySet()){
    31             if(!visited.contains(node)){
    32                 boolean flag = hasCycleDFSUtil(node, visited, -1, graph);
    33                 if(flag){
    34                     return true;
    35                 }
    36             }
    37         }
    38         return false;
    39     }
    40     private boolean hasCycleDFSUtil(int node, 
    41                                     HashSet<Integer> visited, 
    42                                     int parent,
    43                                     HashMap<Integer, HashSet<Integer>> graph){
    44         visited.add(node);
    45         for(Integer neighbor : graph.get(node)){
    46             //if we skil this check, then when the logic check its parent node
    47             //it will mistakenly think a cycle is found. 
    48             //e.g, A -- B -- C, start dfs from A. When visiting C, its parent B
    49             //has been added to the visited set, if we only rely on the visited.contains(B)
    50             //check, it will cause this method return true. We should only return true
    51             //when its neighbor has been visited and this neighbor is not its parent node
    52             if(neighbor == parent){
    53                 continue;
    54             }    
    55             if(visited.contains(neighbor)){
    56                 return true;
    57             }
    58             boolean hasCycle = hasCycleDFSUtil(neighbor, visited, node, graph);
    59             if(hasCycle){
    60                 return true;
    61             }
    62         }
    63         return false;
    64     }
    65 }

    Solution 4. Union Find

     1 //Algorithm 4.  Union Find, O(m + n) time, O(n) space, m is the number of edges
     2 // n is the number of nodes
     3 class UnionFind {
     4     private int[] father = null;
     5     private int count = 0;
     6     public UnionFind(int n){
     7         father = new int[n];
     8         count = n;
     9         for(int i = 0; i < n; i++){
    10             father[i] = i;
    11         }
    12     }
    13     public int find(int x){
    14         if(father[x] == x){
    15             return x;
    16         }
    17         return father[x] = find(father[x]);
    18     }
    19     public void connect(int a, int b){
    20         int root_a = find(a);
    21         int root_b = find(b);
    22         if(root_a != root_b){
    23             father[root_a] = father[root_b];
    24             count--;
    25         }
    26     }
    27     public int queryCount(){
    28         return count;
    29     }
    30 }    
    31 public class Solution {
    32     public boolean validTree(int n, int[][] edges) {
    33         if(edges.length != n - 1)
    34         {
    35             return false;
    36         }
    37         UnionFind uf = new UnionFind(n);
    38         for(int i = 0; i < edges.length; i++){
    39             uf.connect(edges[i][0], edges[i][1]);
    40         }
    41         return uf.queryCount() == 1;
    42     }
    43 }

    Related Problems

    Connecting Graph

    Connected Component in Undirected Graph

  • 相关阅读:
    RxSwift 核心
    用 @media 控制图片显示大小
    关于媒体查询 @media 的用法
    再次搞懂弹性盒模型
    由淘宝想起,在css无法加载的情况下 依旧可以点击链接调整
    nth-child()和nth-of-type 用法
    如何消除img间的默认间隙
    由淘宝鼠标经过显示头像想起的 定位分析
    水平居中和垂直居中
    position 和 transform【鼠标经过显示一个div滑过】&导航效果应用 以及定位自己的总结
  • 原文地址:https://www.cnblogs.com/lz87/p/7496906.html
Copyright © 2011-2022 走看看