Problem
There is a bi-directional graph with n
vertices, where each vertex is labeled from 0
to n - 1
(inclusive). The edges in the graph are represented as a 2D integer array edges
, where each edges[i] = [ui, vi]
denotes a bi-directional edge between vertex ui
and vertex vi
. Every vertex pair is connected by at most one edge, and no vertex has an edge to itself.
You want to determine if there is a valid path that exists from vertex source
to vertex destination
.
Given edges
and the integers n
, source
, and destination
, return true
if there is a valid path from source
to destination
, or false
otherwise_._
Examples
Example 1:
graph LR; 0 --> 1 --> 2 --> 0
Input: n = 3, edges =[[0,1],[1,2],[2,0]], source = 0, destination = 2
Output: true
Explanation: There is one path from vertex 0 to vertex 2:
- 0 → 1 → 2
Example 2:
graph LR; 2 <-- 0 --> 1 3 --> 5 --> 4 --> 3
Input: n = 6, edges =[[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5
Output: false
Explanation: There is no path from vertex 0 to vertex 5.
Similar Problem
This problem is similar to Find if Path Exists in Graph Problem, just that there the graph is bi-directional, and here it is directed or uni-directional.
Solutions
Method 1 - BFS
BFS can be used to check if one node is reachable from other :
Add V1 to a queue of nodes to be visited
While there are nodes in the queue:
If the node is V2, return true
Mark the node as visited
For every node at the end of an outgoing edge which is not yet visited:
Add this node to the queue
End for
End while
Return false
Code
Java
public boolean validPath(int n, int[][] edges, int source, int destination) {
if (source == destination) {
return true;
}
Map<Integer, List<Integer>> g = new HashMap<>();
for (int i = 0; i < n; i++) {
g.put(i, new LinkedList<>());
}
for (int[] edge: edges) {
int src = edge[0];
int dest = edge[1];
// uni-directioanl, so just 1 edge
g.get(src).add(dest);
}
Queue<Integer> queue = new LinkedList();
queue.add(source);
Set<Integer> visited = new HashSet<>();
while(!queue.isEmpty()) {
int curr = queue.poll();
visited.add(curr);
for(int nei: g.get(curr)) {
if (nei == destination) {
return true;
}
if (visited.contains(nei)) {
continue;
}
queue.add(nei);
}
}
return false;
}
Method 2 - DFS
Code
Java
public boolean validPath(int n, int[][] edges, int source, int destination) {
if (source == destination) {
return true;
}
Map<Integer, List<Integer>> g = new HashMap<>();
for (int i = 0; i < n; i++) {
g.put(i, new LinkedList<>());
}
for (int[] edge: edges) {
int src = edge[0];
int dest = edge[1];
// uni-directioanl, so just 1 edge
g.get(src).add(dest);
}
Stack<Integer> stk = new Stack<>();
stk.add(source);
Set<Integer> visited = new HashSet<>();
while(!stk.isEmpty()) {
int curr = stk.pop();
visited.add(curr);
for(int nei: g.get(curr)) {
if (nei == destination) {
return true;
}
if (visited.contains(nei)) {
continue;
}
stk.add(nei);
}
}
return false;
}
Method 3 - Union Find OR Disjoint Set
Code
Java
class DisjointSetUnion{
private int[] parent;
private int[] rank;
private int N;
public DisjointSetUnion(int n){
this.N = n;
this.parent = new int[this.N];
this.rank = new int[this.N];
for(int i = 0; i < this.N; i++){
this.parent[i] = i;
this.rank[i] = 1;
}
}
public boolean areConnected(int u, int v){
return find(u) == find(v);
}
public void union(int u, int v){
if(u != v){
int a = find(u);
int b = find(v);
if(a != b){
if(rank[a] > rank[b]){
parent[b] = a;
rank[a] += rank[b];
}else{
parent[a] = b;
rank[b] += rank[a];
}
}
}
}
private int find(int u){
int x = u;
while(x != this.parent[x]){
x = this.parent[x];
}
this.parent[u] = x;
return x;
}
}
class Solution {
public boolean validPath(int n, int[][] edges, int start, int end) {
DisjointSetUnion set = new DisjointSetUnion(n);
for(int[] edge : edges){
set.union(edge[0], edge[1]);
}
return set.areConnected(start, end);
}
}
Complexity
- Time complexity = O(E log V)