1971. Find if Path Exists in Graph
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.
Example 1:
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:
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.
Constraints:
1 <= n <= 2 * 105
0 <= edges.length <= 2 * 105
edges[i].length == 2
0 <= ui, vi <= n - 1
ui != vi
0 <= source, destination <= n - 1
- There are no duplicate edges.
- There are no self edges.
Solution:
DFS
stack:
class Solution {
public boolean validPath(int n, int[][] edges, int source, int destination) {
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < n; i++){
graph.put(i, new ArrayList<>());
}
for (int[] edge : edges){
int from = edge[0];
int to = edge[1];
graph.get(from).add(to);
graph.get(to).add(from);
}
Deque<Integer> stack = new ArrayDeque<Integer>();
stack.offerLast(source);
Set<Integer> visited = new HashSet<>();
while(!stack.isEmpty()){
int node = stack.pollLast();
if (node == destination){
return true;
}
if (visited.contains(node)){
continue;
}
visited.add(node);
for (int nei : graph.get(node)){
stack.offerLast(nei);
}
}
return false;
}
}
// TC: O(V+E)
// SC: O(V+E)
recursion:
class Solution {
public boolean validPath(int n, int[][] edges, int source, int destination) {
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < n; i++){
graph.put(i, new ArrayList<Integer>());
}
for (int[] edge : edges){
int from = edge[0];
int to = edge[1];
graph.get(from).add(to);
graph.get(to).add(from);
}
Set<Integer> visited = new HashSet<>();
return dfs(graph, source, destination, visited);
}
private boolean dfs(Map<Integer, List<Integer>> graph, int source, int destination, Set<Integer> visited){
if (visited.contains(source)){
return false;
}
visited.add(source);
if (source == destination){
return true;
}
for (int next : graph.get(source)){
if (dfs(graph, next, destination, visited)){
return true;
}
}
// visited.remove(source);
return false;
}
}
// TC: O(V+E)
// SC: O(V+E)
BFS
class Solution {
public boolean validPath(int n, int[][] edges, int source, int destination) {
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < n; i++){
graph.put(i, new ArrayList<>());
}
for (int[] edge : edges){
int from = edge[0];
int to = edge[1];
graph.get(from).add(to);
graph.get(to).add(from);
}
Deque<Integer> queue = new ArrayDeque<Integer>();
queue.offerLast(source);
Set<Integer> visited = new HashSet<Integer>();
visited.add(source);
while(!queue.isEmpty()){
int cur = queue.pollFirst();
if (cur == destination){
return true;
}
for (int next : graph.get(cur)){
if (!visited.contains(next)){
visited.add(next);
queue.offerLast(next);
}
}
}
return false;
}
}
// TC: O(V+E)
// SC: O(v+E)
UnionFind
class Solution {
public boolean validPath(int n, int[][] edges, int source, int destination) {
UnionFind uf = new UnionFind(n);
for (int[] edge : edges){
if (uf.isC(edge[0], edge[1]) == false){
uf.union(edge[0], edge[1]);
}
}
return uf.isC(source, destination);
}
}
class UnionFind{
int[] root;
public UnionFind(int n){
root = new int[n];
for (int i = 0; i < n; i++){
root[i] = i;
}
}
public int find(int x){
while(x != root[x]){
x = root[x];
}
return x;
}
public void union(int x, int y){
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY){
root[rootY] = rootX;
}
}
public boolean isC(int x, int y){
return find(x) == find(y);
}
}
// TLM
Improve use rank:
class Solution {
public boolean validPath(int n, int[][] edges, int source, int destination) {
UnionFind uf = new UnionFind(n);
for (int[] edge : edges){
if (uf.isC(edge[0], edge[1]) == false){
uf.union(edge[0], edge[1]);
}
}
return uf.isC(source, destination);
}
}
class UnionFind{
int[] root;
int[] rank;
public UnionFind(int n){
root = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++){
root[i] = i;
rank[i] = 1;
}
}
public int find(int x){
while(x != root[x]){
x = root[x];
}
return x;
}
public void union(int x, int y){
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY){
if (rank[rootX] > rank[rootY]){
root[rootY] = rootX;
}else if (rank[rootX] < rank[rootY]){
root[rootX] = rootY;
}else{
root[rootY] = rootX;
rank[rootX]++;
}
}
}
public boolean isC(int x, int y){
return find(x) == find(y);
}
}
// TC: (n+e)
// SC: (n)