Skip to content

Commit 009f473

Browse files
committed
1971-find-if-path-exists-in-graph-2.md Added 2 UnionFind solutions in Python.
1 parent b5979d7 commit 009f473

File tree

2 files changed

+201
-0
lines changed

2 files changed

+201
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# LeetCode 1971. Find if Path Exists in Graph's Solution: UnionFind
2+
LeetCode problem link: [1971. Find if Path Exists in Graph](https://leetcode.com/problems/find-if-path-exists-in-graph)
3+
4+
## LeetCode problem description
5+
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.
6+
7+
You want to determine if there is a **valid path** that exists from vertex `source` to vertex `destination`.
8+
9+
Given `edges` and the integers `n`, `source`, and `destination`, return `true` _if there is a **valid path** from `source` to `destination`, or `false` otherwise_.
10+
11+
### Example 1
12+
![](../../images/examples/1971_1.png)
13+
```
14+
Input: n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2
15+
Output: true
16+
Explanation: There are two paths from vertex 0 to vertex 2:
17+
- 0 → 1 → 2
18+
- 0 → 2
19+
```
20+
21+
### Example 2
22+
![](../../images/examples/1971_2.png)
23+
```
24+
Input: n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5
25+
Output: false
26+
Explanation: There is no path from vertex 0 to vertex 5.
27+
```
28+
29+
### Constraints
30+
- `1 <= n <= 2 * 10**5`
31+
- `0 <= edges.length <= 2 * 10**5`
32+
- `edges[i].length == 2`
33+
- `0 <= ui, vi <= n - 1`
34+
- `ui != vi`
35+
- `0 <= source, destination <= n - 1`
36+
- There are no duplicate edges.
37+
- There are no self edges.
38+
39+
## Another solution: Breadth-First Search Algorithm
40+
Please see [1971. Find if Path Exists in Graph ('Breadth-First Search' Solution)](1971-find-if-path-exists-in-graph.md).
41+
42+
## Intuition
43+
The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**:
44+
45+
![](../../images/graph_undirected_1.svg)
46+
47+
And this graph may have multiple **connected components**. Initially, we start from `source` vertex which belongs to one of the `connected components`.
48+
49+
![](../../images/graph_undirected_2.png)
50+
51+
- We need to find if there is a path from `source` to `destination`. This question is equivalent to determine if `source` and `destination` vertices belong to the same `connected component`.
52+
- A `tree` is a type of `graph`. If two nodes are in the same tree, then return `true`. So we need a method `in_same_tree(node1, node2)` to return a boolean value.
53+
- We are `edges` data and need to divide them into multiple groups, each group can be abstracted into a **tree**.
54+
- `UnionFind` algorithm is designed for grouping and searching data.
55+
56+
### 'UnionFind' algorithm
57+
- `UnionFind` algorithm typically has three methods:
58+
- The `unite(node1, node2)` operation can be used to merge two trees.
59+
- The `find_root(node)` method can be used to return the root of a node.
60+
- The `same_root(node1, node2)` method can be used to judge if two nodes are in the same tree.
61+
62+
## Approach (UnionFind algorithm)
63+
1. Initially, every node is in the group of itself.
64+
1. Iterate `edges` data and `unite(node1, node2)`.
65+
1. Return `same_root(source, destination)`.
66+
67+
## Complexity
68+
* Time: `O(n)`.
69+
* Space: `O(n)`.
70+
71+
## Python
72+
### Standard UnionFind algorithm
73+
```python
74+
class Solution:
75+
def __init__(self):
76+
self.father = None
77+
78+
def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool:
79+
self.father = list(range(n))
80+
81+
for x, y in edges:
82+
self.unite(x, y)
83+
84+
return self.same_root(source, destination)
85+
86+
def unite(self, x, y):
87+
root_x = self.find_root(x)
88+
root_y = self.find_root(y)
89+
90+
self.father[root_y] = root_x # Error-prone point 1
91+
92+
def find_root(self, x):
93+
if x == self.father[x]:
94+
return x
95+
96+
self.father[x] = self.find_root(self.father[x]) # Error-prone point 2
97+
98+
return self.father[x]
99+
100+
def same_root(self, x, y):
101+
return self.find_root(x) == self.find_root(y)
102+
```
103+
104+
### Another UnionFind algorithm (using a map and an array of set)
105+
This solution is slower than the `Standard UnionFind algorithm`, but it is straightforward.
106+
```python
107+
class Solution:
108+
def __init__(self):
109+
self.disjoint_sets = []
110+
self.value_to_set_id = {}
111+
112+
def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool:
113+
for i in range(n):
114+
self.disjoint_sets.append({i})
115+
self.value_to_set_id[i] = i
116+
117+
for x, y in edges:
118+
self.unite(x, y)
119+
120+
return self.in_same_set(source, destination)
121+
122+
def unite(self, x, y):
123+
if self.in_same_set(x, y):
124+
return
125+
126+
bigger = x
127+
smaller = y
128+
129+
if len(self.get_set(x)) < len(self.get_set(y)):
130+
bigger = y
131+
smaller = x
132+
133+
for value in self.get_set(smaller):
134+
self.get_set(bigger).add(value)
135+
self.value_to_set_id[value] = self.value_to_set_id.get(bigger)
136+
137+
def get_set(self, value):
138+
set_id = self.value_to_set_id.get(value)
139+
return self.disjoint_sets[set_id]
140+
141+
def in_same_set(self, x, y):
142+
return self.get_set(x) == self.get_set(y)
143+
```
144+
145+
## Java
146+
```java
147+
// Welcome to create a PR to complete the code of this language, thanks!
148+
```
149+
150+
## C++
151+
```cpp
152+
// Welcome to create a PR to complete the code of this language, thanks!
153+
```
154+
155+
## JavaScript
156+
```javascript
157+
// Welcome to create a PR to complete the code of this language, thanks!
158+
```
159+
160+
## C#
161+
```c#
162+
// Welcome to create a PR to complete the code of this language, thanks!
163+
```
164+
165+
## Go
166+
```go
167+
// Welcome to create a PR to complete the code of this language, thanks!
168+
```
169+
170+
## Ruby
171+
```ruby
172+
# Welcome to create a PR to complete the code of this language, thanks!
173+
```
174+
175+
## C
176+
```c
177+
// Welcome to create a PR to complete the code of this language, thanks!
178+
```
179+
180+
## Kotlin
181+
```kotlin
182+
// Welcome to create a PR to complete the code of this language, thanks!
183+
```
184+
185+
## Swift
186+
```swift
187+
// Welcome to create a PR to complete the code of this language, thanks!
188+
```
189+
190+
## Rust
191+
```rust
192+
// Welcome to create a PR to complete the code of this language, thanks!
193+
```
194+
195+
## Other languages
196+
```
197+
// Welcome to create a PR to complete the code of this language, thanks!
198+
```

solutions/1001-2000/1971-find-if-path-exists-in-graph.md

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Explanation: There is no path from vertex 0 to vertex 5.
3636
- There are no duplicate edges.
3737
- There are no self edges.
3838

39+
## Another solution: UnionFind Algorithm
40+
Please see [1971. Find if Path Exists in Graph (UnionFind Solution)](1971-find-if-path-exists-in-graph-2.md).
41+
3942
## Intuition
4043
The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**:
4144

0 commit comments

Comments
 (0)