Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7b99ea4

Browse files
committed
Graph Valid Tree: done
1 parent c386fbe commit 7b99ea4

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package com.leetcode.graphs;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import static org.junit.jupiter.api.Assertions.assertFalse;
7+
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
9+
/**
10+
* Level: Medium
11+
* Problem Link: https://leetcode.com/problems/graph-valid-tree/
12+
* Problem Description:
13+
* 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
14+
* to check whether these edges make up a valid tree.
15+
* <p>
16+
* Example 1:
17+
* Input: n = 5, and edges = [[0,1], [0,2], [0,3], [1,4]]
18+
* Output: true
19+
* <p>
20+
* Example 2:
21+
* Input: n = 5, and edges = [[0,1], [1,2], [2,3], [1,3], [1,4]]
22+
* Output: false
23+
* <p>
24+
* Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0,1] is the
25+
* same as [1,0] and thus will not appear together in edges.
26+
*
27+
* @author rampatra
28+
* @since 2019年08月05日
29+
*/
30+
public class GraphValidTree {
31+
32+
/**
33+
*
34+
* @param n
35+
* @param edges
36+
* @return
37+
*/
38+
public static boolean isValidTree(int n, int[][] edges) {
39+
List<List<Integer>> adjacencyList = new ArrayList<>(n);
40+
41+
for (int i = 0; i < n; i++) {
42+
adjacencyList.add(new ArrayList<>());
43+
}
44+
45+
for (int i = 0; i < edges.length; i++) {
46+
adjacencyList.get(edges[i][0]).add(edges[i][1]);
47+
}
48+
49+
boolean[] visited = new boolean[n];
50+
51+
if (hasCycle(adjacencyList, 0, -1, visited)) {
52+
return false;
53+
}
54+
55+
for (int i = 0; i < n; i++) {
56+
if (!visited[i]) {
57+
return false;
58+
}
59+
}
60+
61+
return true;
62+
}
63+
64+
private static boolean hasCycle(List<List<Integer>> adjacencyList, int node1, int exclude, boolean[] visited) {
65+
visited[node1] = true;
66+
67+
for (int i = 0; i < adjacencyList.get(node1).size(); i++) {
68+
int node2 = adjacencyList.get(node1).get(i);
69+
70+
if ((visited[node2] && exclude != node2) || (!visited[node2] && hasCycle(adjacencyList, node2, node1, visited))) {
71+
return true;
72+
}
73+
}
74+
75+
return false;
76+
}
77+
78+
79+
/**
80+
* Union-find algorithm: We keep all connected nodes in one set in the union operation and in find operation we
81+
* check whether two nodes belong to the same set. If yes then there's a cycle and if not then no cycle.
82+
*
83+
* Good articles on union-find:
84+
* - https://www.hackerearth.com/practice/notes/disjoint-set-union-union-find/
85+
* - https://www.youtube.com/watch?v=wU6udHRIkcc
86+
*
87+
* @param n
88+
* @param edges
89+
* @return
90+
*/
91+
public static boolean isValidTreeUsingUnionFind(int n, int[][] edges) {
92+
int[] roots = new int[n];
93+
94+
for (int i = 0; i < n; i++) {
95+
roots[i] = i;
96+
}
97+
98+
for (int i = 0; i < edges.length; i++) {
99+
// find operation
100+
if (roots[edges[i][0]] == roots[edges[i][1]]) {
101+
return false;
102+
}
103+
// union operation
104+
roots[edges[i][1]] = findRoot(roots, roots[edges[i][0]]); // note: we can optimize this even further by
105+
// considering size of each side and then join the side with smaller size to the one with a larger size (weighted union).
106+
// We can use another array called size to keep count of the size or we can use the same root array with
107+
// negative values, i.e, negative resembles that the node is pointing to itself and the number will represent
108+
// the size. For example, roots = [-2, -1, -1, 0] means that node 3 is pointing to node 0 and node 0 is pointing
109+
// to itself and is has 2 nodes under it including itself.
110+
}
111+
112+
return edges.length == n - 1;
113+
}
114+
115+
private static int findRoot(int[] roots, int node) {
116+
while (roots[node] != node) {
117+
node = roots[node];
118+
}
119+
return node;
120+
}
121+
122+
public static void main(String[] args) {
123+
assertTrue(isValidTree(5, new int[][]{{0, 1}, {0, 2}, {0, 3}, {1, 4}}));
124+
assertFalse(isValidTree(5, new int[][]{{0, 1}, {1, 2}, {2, 3}, {1, 3}, {1, 4}}));
125+
assertFalse(isValidTree(3, new int[][]{{0, 1}, {1, 2}, {2, 0}}));
126+
127+
assertTrue(isValidTreeUsingUnionFind(5, new int[][]{{0, 1}, {0, 2}, {0, 3}, {1, 4}}));
128+
assertFalse(isValidTreeUsingUnionFind(5, new int[][]{{0, 1}, {1, 2}, {2, 3}, {1, 3}, {1, 4}}));
129+
assertFalse(isValidTreeUsingUnionFind(3, new int[][]{{0, 1}, {1, 2}, {2, 0}}));
130+
}
131+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /