package com.freetymekiyan.algorithms.level.medium; /** * 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. * <p> * For example: * <p> * Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true. * <p> * Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false. * <p> * Hint: * <p> * Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], what should your return? Is this case a valid tree? * According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are * connected by exactly one path. In other words, any connected graph without simple cycles is a tree.” * 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. * <p> * Company Tags: Google, Facebook, Zenefits * Tags: Depth-first Search, Breadth-first Search, Graph, Union Find * Similar Problems: (M) Course Schedule, (M) Number of Connected Components in an Undirected Graph */ public class GraphValidTree { /** * Union Find. * What is the difference between tree and graph? * Tree is a special graph: 1) All connected. 2) No cycle. Connected acyclic graph. * Union-find can be used to build connected component and check connection. * <p> * Implementation: * Quick check: It requires n-1 edges to connect n vertices. So if edges.length != n-1, return false. * Initialize an array of connected component ids. * For each edge in edges: * | Find the connected component ids for the two nodes. * | If the ids are the same, the two nodes are already connected, return false. * | Else, union the two nodes by set x's id to y. * After checking all edges, return true. */ public boolean validTree(int n, int[][] edges) { // Quick check on the number of edges. It requires n - 1 edges to connect n vertices. if (edges.length != n - 1) { return false; } // Init cc id array. int[] nums = new int[n]; for (int i = 0; i < n; i++) { nums[i] = i; } // Check cycle. for (int i = 0; i < edges.length; i++) { // Find connected component ids of the two nodes. int x = find(nums, edges[i][0]); int y = find(nums, edges[i][1]); if (x == y) { // If two vertices are already connected. return false; } // Union nums[x] = y; // Add edges[i][0] to the connected component. } return true; } /** * Recursive. * Find connected component id, or the root id. * Check whether child(current index) and parent(the value) are the same. * If they are, return the index. * If not, set index to the value and check again. * Stop till we find the root. */ private int find(int nums[], int i) { while (i != nums[i]) { // Here if we found the child's id are not the same as the parent's. // We know the parent can be an intermediate id. // So we set parent's id to grand parent's id. // Which will dynamically balance the tree thus reducing O(n) to O(1). nums[i] = nums[nums[i]]; i = nums[i]; } return i; } }