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 nsource, and destination, return true if there is a valid path from source to destination, or false otherwise_._

Examples

Example 1:

0 --- 1
 \   /
  \ /
   2
Input: n = 3, edges =[[0,1],[1,2],[2,0]], source = 0, destination = 2
Output: true
Explanation: There are two paths from vertex 0 to vertex 2:
- 0 → 1 → 2
- 0 → 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 Directed Graph Problem, just that here the graph is bi-directional and there it is directed or uni-directional.

Solutions

Detailed Video Explanation:

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];

		g.get(src).add(dest);
		g.get(dest).add(src);
	}
	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];

		g.get(src).add(dest);
		g.get(dest).add(src);
	}
	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)