diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/README.md b/solution/1900-1999/1971.Find if Path Exists in Graph/README.md
index b31c2f87b0253..495d78e0fb30e 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/README.md
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/README.md
@@ -33,7 +33,7 @@ tags:
输入:n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2
输出:true
解释:存在由顶点 0 到顶点 2 的路径:
-- 0 → 1 → 2
+- 0 → 1 → 2
- 0 → 2
@@ -68,9 +68,9 @@ tags:
### 方法一:DFS
-我们先将 `edges` 转换成邻接表 $g$,然后使用 DFS,判断是否存在从 `source` 到 `destination` 的路径。
+我们首先将 $\textit{edges}$ 转换成邻接表 $g$,然后使用 DFS,判断是否存在从 $\textit{source}$ 到 $\textit{destination}$ 的路径。
-过程中,我们用数组 `vis` 记录已经访问过的顶点,避免重复访问。
+过程中,我们用数组 $\textit{vis}$ 记录已经访问过的顶点,避免重复访问。
时间复杂度 $O(n + m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别是节点数和边数。
@@ -83,7 +83,7 @@ class Solution:
def validPath(
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
- def dfs(i):
+ def dfs(i: int) -> bool:
if i == destination:
return True
vis.add(i)
@@ -93,9 +93,9 @@ class Solution:
return False
g = [[] for _ in range(n)]
- for a, b in edges:
- g[a].append(b)
- g[b].append(a)
+ for u, v in edges:
+ g[u].append(v)
+ g[v].append(u)
vis = set()
return dfs(source)
```
@@ -109,15 +109,15 @@ class Solution {
private List[] g;
public boolean validPath(int n, int[][] edges, int source, int destination) {
+ this.destination = destination;
+ vis = new boolean[n];
g = new List[n];
- Arrays.setAll(g, k -> new ArrayList<>());
+ Arrays.setAll(g, i -> new ArrayList<>());
for (var e : edges) {
- int a = e[0], b = e[1];
- g[a].add(b);
- g[b].add(a);
+ int u = e[0], v = e[1];
+ g[u].add(v);
+ g[v].add(u);
}
- vis = new boolean[n];
- this.destination = destination;
return dfs(source);
}
@@ -126,7 +126,7 @@ class Solution {
return true;
}
vis[i] = true;
- for (int j : g[i]) {
+ for (var j : g[i]) {
if (!vis[j] && dfs(j)) {
return true;
}
@@ -142,19 +142,19 @@ class Solution {
class Solution {
public:
bool validPath(int n, vector>& edges, int source, int destination) {
- vector vis(n);
vector g[n];
- for (auto& e : edges) {
- int a = e[0], b = e[1];
- g[a].emplace_back(b);
- g[b].emplace_back(a);
+ vector vis(n);
+ for (const auto& e : edges) {
+ int u = e[0], v = e[1];
+ g[u].push_back(v);
+ g[v].push_back(u);
}
function dfs = [&](int i) -> bool {
if (i == destination) {
return true;
}
vis[i] = true;
- for (int& j : g[i]) {
+ for (int j : g[i]) {
if (!vis[j] && dfs(j)) {
return true;
}
@@ -173,9 +173,9 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
vis := make([]bool, n)
g := make([][]int, n)
for _, e := range edges {
- a, b := e[0], e[1]
- g[a] = append(g[a], b)
- g[b] = append(g[b], a)
+ u, v := e[0], e[1]
+ g[u] = append(g[u], v)
+ g[v] = append(g[v], u)
}
var dfs func(int) bool
dfs = func(i int) bool {
@@ -199,11 +199,10 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
```ts
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
const g: number[][] = Array.from({ length: n }, () => []);
- for (const [a, b] of edges) {
- g[a].push(b);
- g[b].push(a);
+ for (const [u, v] of edges) {
+ g[u].push(v);
+ g[v].push(u);
}
-
const vis = new Set();
const dfs = (i: number) => {
if (i === destination) {
@@ -212,11 +211,9 @@ function validPath(n: number, edges: number[][], source: number, destination: nu
if (vis.has(i)) {
return false;
}
-
vis.add(i);
return g[i].some(dfs);
};
-
return dfs(source);
}
```
@@ -224,35 +221,37 @@ function validPath(n: number, edges: number[][], source: number, destination: nu
#### Rust
```rust
-use std::collections::HashSet;
-
impl Solution {
pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
- let mut vis = vec![false; n as usize];
- let mut g = vec![HashSet::new(); n as usize];
+ let n = n as usize;
+ let source = source as usize;
+ let destination = destination as usize;
+
+ let mut g = vec![Vec::new(); n];
+ let mut vis = vec![false; n];
for e in edges {
- let a = e[0] as usize;
- let b = e[1] as usize;
- g[a].insert(b);
- g[b].insert(a);
+ let u = e[0] as usize;
+ let v = e[1] as usize;
+ g[u].push(v);
+ g[v].push(u);
}
- dfs(source as usize, destination as usize, &mut vis, &g)
- }
-}
-
-fn dfs(i: usize, destination: usize, vis: &mut Vec, g: &Vec>) -> bool {
- if i == destination {
- return true;
- }
- vis[i] = true;
- for &j in &g[i] {
- if !vis[j] && dfs(j, destination, vis, g) {
- return true;
+ fn dfs(g: &Vec>, vis: &mut Vec, i: usize, destination: usize) -> bool {
+ if i == destination {
+ return true;
+ }
+ vis[i] = true;
+ for &j in &g[i] {
+ if !vis[j] && dfs(g, vis, j, destination) {
+ return true;
+ }
+ }
+ false
}
+
+ dfs(&g, &mut vis, source, destination)
}
- false
}
```
@@ -264,13 +263,13 @@ fn dfs(i: usize, destination: usize, vis: &mut Vec, g: &Vec
### 方法二:BFS
-我们也可以使用 BFS,判断是否存在从 `source` 到 `destination` 的路径。
+我们也可以使用 BFS,判断是否存在从 $\textit{source}$ 到 $\textit{destination}$ 的路径。
-具体地,我们定义一个队列 $q$,初始时将 `source` 加入队列。另外,我们用一个集合 `vis` 记录已经访问过的顶点,避免重复访问。
+具体地,我们定义一个队列 $q$,初始时将 $\textit{source}$ 加入队列。另外,我们用一个集合 $\textit{vis}$ 记录已经访问过的顶点,避免重复访问。
-接下来,我们不断从队列中取出顶点 $i$,如果 $i = \textit{destination}$,则说明存在从 `source` 到 `destination` 的路径,返回 `true`。否则,我们遍历 $i$ 的所有邻接顶点 $j$,如果 $j$ 没有被访问过,我们将 $j$ 加入队列 $q$,并且标记 $j$ 为已访问。
+接下来,我们不断从队列中取出顶点 $i$,如果 $i = \textit{destination}$,则说明存在从 $\textit{source}$ 到 $\textit{destination}$ 的路径,返回 $\textit{true}$。否则,我们遍历 $i$ 的所有邻接顶点 $j$,如果 $j$ 没有被访问过,我们将 $j$ 加入队列 $q$,并且标记 $j$ 为已访问。
-最后,如果队列为空,说明不存在从 `source` 到 `destination` 的路径,返回 `false`。
+最后,如果队列为空,说明不存在从 $\textit{source}$ 到 $\textit{destination}$ 的路径,返回 $\textit{false}$。
时间复杂度 $O(n + m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别是节点数和边数。
@@ -284,10 +283,9 @@ class Solution:
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
g = [[] for _ in range(n)]
- for a, b in edges:
- g[a].append(b)
- g[b].append(a)
-
+ for u, v in edges:
+ g[u].append(v)
+ g[v].append(u)
q = deque([source])
vis = {source}
while q:
@@ -309,9 +307,9 @@ class Solution {
List[] g = new List[n];
Arrays.setAll(g, k -> new ArrayList<>());
for (var e : edges) {
- int a = e[0], b = e[1];
- g[a].add(b);
- g[b].add(a);
+ int u = e[0], v = e[1];
+ g[u].add(v);
+ g[v].add(u);
}
Deque q = new ArrayDeque<>();
q.offer(source);
@@ -341,10 +339,10 @@ class Solution {
public:
bool validPath(int n, vector>& edges, int source, int destination) {
vector> g(n);
- for (auto& e : edges) {
- int a = e[0], b = e[1];
- g[a].push_back(b);
- g[b].push_back(a);
+ for (const auto& e : edges) {
+ int u = e[0], v = e[1];
+ g[u].push_back(v);
+ g[v].push_back(u);
}
queue q{{source}};
vector vis(n);
@@ -373,9 +371,9 @@ public:
func validPath(n int, edges [][]int, source int, destination int) bool {
g := make([][]int, n)
for _, e := range edges {
- a, b := e[0], e[1]
- g[a] = append(g[a], b)
- g[b] = append(g[b], a)
+ u, v := e[0], e[1]
+ g[u] = append(g[u], v)
+ g[v] = append(g[v], u)
}
q := []int{source}
vis := make([]bool, n)
@@ -402,27 +400,24 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
```ts
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
const g: number[][] = Array.from({ length: n }, () => []);
-
- for (const [a, b] of edges) {
- g[a].push(b);
- g[b].push(a);
+ for (const [u, v] of edges) {
+ g[u].push(v);
+ g[v].push(u);
}
-
- const vis = new Set();
+ const vis = new Set([source]);
const q = [source];
-
while (q.length) {
const i = q.pop()!;
if (i === destination) {
return true;
}
- if (vis.has(i)) {
- continue;
+ for (const j of g[i]) {
+ if (!vis.has(j)) {
+ vis.add(j);
+ q.push(j);
+ }
}
- vis.add(i);
- q.push(...g[i]);
}
-
return false;
}
```
@@ -434,26 +429,30 @@ use std::collections::{HashSet, VecDeque};
impl Solution {
pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
- let mut g = vec![HashSet::new(); n as usize];
- for e in edges {
- let a = e[0] as usize;
- let b = e[1] as usize;
- g[a].insert(b);
- g[b].insert(a);
+ let n = n as usize;
+ let source = source as usize;
+ let destination = destination as usize;
+
+ let mut g = vec![Vec::new(); n];
+ for edge in edges {
+ let u = edge[0] as usize;
+ let v = edge[1] as usize;
+ g[u].push(v);
+ g[v].push(u);
}
let mut q = VecDeque::new();
- q.push_back(source as usize);
- let mut vis = vec![false; n as usize];
- vis[source as usize] = true;
+ let mut vis = HashSet::new();
+ q.push_back(source);
+ vis.insert(source);
while let Some(i) = q.pop_front() {
- if i == (destination as usize) {
+ if i == destination {
return true;
}
for &j in &g[i] {
- if !vis[j] {
- vis[j] = true;
+ if !vis.contains(&j) {
+ vis.insert(j);
q.push_back(j);
}
}
@@ -486,65 +485,130 @@ impl Solution {
#### Python3
```python
+class UnionFind:
+ def __init__(self, n):
+ self.p = list(range(n))
+ self.size = [1] * n
+
+ def find(self, x):
+ if self.p[x] != x:
+ self.p[x] = self.find(self.p[x])
+ return self.p[x]
+
+ def union(self, a, b):
+ pa, pb = self.find(a), self.find(b)
+ if pa == pb:
+ return False
+ if self.size[pa] > self.size[pb]:
+ self.p[pb] = pa
+ self.size[pa] += self.size[pb]
+ else:
+ self.p[pa] = pb
+ self.size[pb] += self.size[pa]
+ return True
+
+
class Solution:
def validPath(
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
- def find(x):
- if p[x] != x:
- p[x] = find(p[x])
- return p[x]
-
- p = list(range(n))
+ uf = UnionFind(n)
for u, v in edges:
- p[find(u)] = find(v)
- return find(source) == find(destination)
+ uf.union(u, v)
+ return uf.find(source) == uf.find(destination)
```
#### Java
```java
-class Solution {
+class UnionFind {
private int[] p;
+ private int[] size;
- public boolean validPath(int n, int[][] edges, int source, int destination) {
+ public UnionFind(int n) {
p = new int[n];
+ size = new int[n];
for (int i = 0; i < n; ++i) {
p[i] = i;
+ size[i] = 1;
}
- for (int[] e : edges) {
- p[find(e[0])] = find(e[1]);
- }
- return find(source) == find(destination);
}
- private int find(int x) {
+ public int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
+
+ public void union(int a, int b) {
+ int pa = find(a), pb = find(b);
+ if (pa != pb) {
+ if (size[pa] > size[pb]) {
+ p[pb] = pa;
+ size[pa] += size[pb];
+ } else {
+ p[pa] = pb;
+ size[pb] += size[pa];
+ }
+ }
+ }
+}
+
+class Solution {
+ public boolean validPath(int n, int[][] edges, int source, int destination) {
+ UnionFind uf = new UnionFind(n);
+ for (var e : edges) {
+ uf.union(e[0], e[1]);
+ }
+ return uf.find(source) == uf.find(destination);
+ }
}
```
#### C++
```cpp
-class Solution {
+class UnionFind {
public:
- bool validPath(int n, vector>& edges, int source, int destination) {
- vector p(n);
+ UnionFind(int n) {
+ p = vector(n);
+ size = vector(n, 1);
iota(p.begin(), p.end(), 0);
- function find = [&](int x) -> int {
- if (p[x] != x) {
- p[x] = find(p[x]);
+ }
+
+ void unite(int a, int b) {
+ int pa = find(a), pb = find(b);
+ if (pa != pb) {
+ if (size[pa] > size[pb]) {
+ p[pb] = pa;
+ size[pa] += size[pb];
+ } else {
+ p[pa] = pb;
+ size[pb] += size[pa];
}
- return p[x];
- };
- for (auto& e : edges) {
- p[find(e[0])] = find(e[1]);
}
- return find(source) == find(destination);
+ }
+
+ int find(int x) {
+ if (p[x] != x) {
+ p[x] = find(p[x]);
+ }
+ return p[x];
+ }
+
+private:
+ vector p, size;
+};
+
+class Solution {
+public:
+ bool validPath(int n, vector>& edges, int source, int destination) {
+ UnionFind uf(n);
+ for (const auto& e : edges) {
+ uf.unite(e[0], e[1]);
+ }
+ return uf.find(source) == uf.find(destination);
}
};
```
@@ -552,40 +616,144 @@ public:
#### Go
```go
-func validPath(n int, edges [][]int, source int, destination int) bool {
+type unionFind struct {
+ p, size []int
+}
+
+func newUnionFind(n int) *unionFind {
p := make([]int, n)
+ size := make([]int, n)
for i := range p {
p[i] = i
+ size[i] = 1
}
- var find func(x int) int
- find = func(x int) int {
- if p[x] != x {
- p[x] = find(p[x])
- }
- return p[x]
+ return &unionFind{p, size}
+}
+
+func (uf *unionFind) find(x int) int {
+ if uf.p[x] != x {
+ uf.p[x] = uf.find(uf.p[x])
+ }
+ return uf.p[x]
+}
+
+func (uf *unionFind) union(a, b int) bool {
+ pa, pb := uf.find(a), uf.find(b)
+ if pa == pb {
+ return false
}
+ if uf.size[pa] > uf.size[pb] {
+ uf.p[pb] = pa
+ uf.size[pa] += uf.size[pb]
+ } else {
+ uf.p[pa] = pb
+ uf.size[pb] += uf.size[pa]
+ }
+ return true
+}
+
+func validPath(n int, edges [][]int, source int, destination int) bool {
+ uf := newUnionFind(n)
for _, e := range edges {
- p[find(e[0])] = find(e[1])
+ uf.union(e[0], e[1])
}
- return find(source) == find(destination)
+ return uf.find(source) == uf.find(destination)
}
```
#### TypeScript
```ts
+class UnionFind {
+ p: number[];
+ size: number[];
+ constructor(n: number) {
+ this.p = Array(n)
+ .fill(0)
+ .map((_, i) => i);
+ this.size = Array(n).fill(1);
+ }
+
+ find(x: number): number {
+ if (this.p[x] !== x) {
+ this.p[x] = this.find(this.p[x]);
+ }
+ return this.p[x];
+ }
+
+ union(a: number, b: number): boolean {
+ const [pa, pb] = [this.find(a), this.find(b)];
+ if (pa === pb) {
+ return false;
+ }
+ if (this.size[pa] > this.size[pb]) {
+ this.p[pb] = pa;
+ this.size[pa] += this.size[pb];
+ } else {
+ this.p[pa] = pb;
+ this.size[pb] += this.size[pa];
+ }
+ return true;
+ }
+}
+
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
- const p: number[] = Array.from({ length: n }, (_, i) => i);
- const find = (x: number): number => {
- if (p[x] !== x) {
- p[x] = find(p[x]);
+ const uf = new UnionFind(n);
+ edges.forEach(([u, v]) => uf.union(u, v));
+ return uf.find(source) === uf.find(destination);
+}
+```
+
+#### Rust
+
+```rust
+struct UnionFind {
+ p: Vec,
+ size: Vec,
+}
+
+impl UnionFind {
+ fn new(n: usize) -> Self {
+ let p = (0..n).collect();
+ let size = vec![1; n];
+ UnionFind { p, size }
+ }
+
+ fn find(&mut self, x: usize) -> usize {
+ if self.p[x] != x {
+ self.p[x] = self.find(self.p[x]);
}
- return p[x];
- };
- for (const [a, b] of edges) {
- p[find(a)] = find(b);
+ self.p[x]
+ }
+
+ fn union(&mut self, a: usize, b: usize) {
+ let pa = self.find(a);
+ let pb = self.find(b);
+ if pa != pb {
+ if self.size[pa] > self.size[pb] {
+ self.p[pb] = pa;
+ self.size[pa] += self.size[pb];
+ } else {
+ self.p[pa] = pb;
+ self.size[pb] += self.size[pa];
+ }
+ }
+ }
+}
+
+impl Solution {
+ pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
+ let n = n as usize;
+ let mut uf = UnionFind::new(n);
+
+ for e in edges {
+ let u = e[0] as usize;
+ let v = e[1] as usize;
+ uf.union(u, v);
+ }
+
+ uf.find(source as usize) == uf.find(destination as usize)
}
- return find(source) === find(destination);
}
```
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/README_EN.md b/solution/1900-1999/1971.Find if Path Exists in Graph/README_EN.md
index 90c191aa18fcb..028e6c866aa70 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/README_EN.md
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/README_EN.md
@@ -66,11 +66,11 @@ tags:
### Solution 1: DFS
-First, we convert `edges` into an adjacency list $g$, then use DFS to determine whether there is a path from `source` to `destination`.
+We first convert $\textit{edges}$ into an adjacency list $g$, then use DFS to determine whether there is a path from $\textit{source}$ to $\textit{destination}$.
-During the process, we use an array `vis` to record the vertices that have been visited to avoid repeated visits.
+During the process, we use an array $\textit{vis}$ to record the vertices that have already been visited to avoid revisiting them.
-The time complexity is $O(n + m)$, and the space complexity is $O(n + m)$. Where $n$ and $m$ are the number of nodes and edges, respectively.
+The time complexity is $O(n + m)$, and the space complexity is $O(n + m)$. Here, $n$ and $m$ are the number of nodes and edges, respectively.
@@ -81,7 +81,7 @@ class Solution:
def validPath(
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
- def dfs(i):
+ def dfs(i: int) -> bool:
if i == destination:
return True
vis.add(i)
@@ -91,9 +91,9 @@ class Solution:
return False
g = [[] for _ in range(n)]
- for a, b in edges:
- g[a].append(b)
- g[b].append(a)
+ for u, v in edges:
+ g[u].append(v)
+ g[v].append(u)
vis = set()
return dfs(source)
```
@@ -107,15 +107,15 @@ class Solution {
private List[] g;
public boolean validPath(int n, int[][] edges, int source, int destination) {
+ this.destination = destination;
+ vis = new boolean[n];
g = new List[n];
- Arrays.setAll(g, k -> new ArrayList<>());
+ Arrays.setAll(g, i -> new ArrayList<>());
for (var e : edges) {
- int a = e[0], b = e[1];
- g[a].add(b);
- g[b].add(a);
+ int u = e[0], v = e[1];
+ g[u].add(v);
+ g[v].add(u);
}
- vis = new boolean[n];
- this.destination = destination;
return dfs(source);
}
@@ -124,7 +124,7 @@ class Solution {
return true;
}
vis[i] = true;
- for (int j : g[i]) {
+ for (var j : g[i]) {
if (!vis[j] && dfs(j)) {
return true;
}
@@ -140,19 +140,19 @@ class Solution {
class Solution {
public:
bool validPath(int n, vector>& edges, int source, int destination) {
- vector vis(n);
vector g[n];
- for (auto& e : edges) {
- int a = e[0], b = e[1];
- g[a].emplace_back(b);
- g[b].emplace_back(a);
+ vector vis(n);
+ for (const auto& e : edges) {
+ int u = e[0], v = e[1];
+ g[u].push_back(v);
+ g[v].push_back(u);
}
function dfs = [&](int i) -> bool {
if (i == destination) {
return true;
}
vis[i] = true;
- for (int& j : g[i]) {
+ for (int j : g[i]) {
if (!vis[j] && dfs(j)) {
return true;
}
@@ -171,9 +171,9 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
vis := make([]bool, n)
g := make([][]int, n)
for _, e := range edges {
- a, b := e[0], e[1]
- g[a] = append(g[a], b)
- g[b] = append(g[b], a)
+ u, v := e[0], e[1]
+ g[u] = append(g[u], v)
+ g[v] = append(g[v], u)
}
var dfs func(int) bool
dfs = func(i int) bool {
@@ -197,11 +197,10 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
```ts
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
const g: number[][] = Array.from({ length: n }, () => []);
- for (const [a, b] of edges) {
- g[a].push(b);
- g[b].push(a);
+ for (const [u, v] of edges) {
+ g[u].push(v);
+ g[v].push(u);
}
-
const vis = new Set();
const dfs = (i: number) => {
if (i === destination) {
@@ -210,11 +209,9 @@ function validPath(n: number, edges: number[][], source: number, destination: nu
if (vis.has(i)) {
return false;
}
-
vis.add(i);
return g[i].some(dfs);
};
-
return dfs(source);
}
```
@@ -222,35 +219,37 @@ function validPath(n: number, edges: number[][], source: number, destination: nu
#### Rust
```rust
-use std::collections::HashSet;
-
impl Solution {
pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
- let mut vis = vec![false; n as usize];
- let mut g = vec![HashSet::new(); n as usize];
+ let n = n as usize;
+ let source = source as usize;
+ let destination = destination as usize;
+
+ let mut g = vec![Vec::new(); n];
+ let mut vis = vec![false; n];
for e in edges {
- let a = e[0] as usize;
- let b = e[1] as usize;
- g[a].insert(b);
- g[b].insert(a);
+ let u = e[0] as usize;
+ let v = e[1] as usize;
+ g[u].push(v);
+ g[v].push(u);
}
- dfs(source as usize, destination as usize, &mut vis, &g)
- }
-}
-
-fn dfs(i: usize, destination: usize, vis: &mut Vec, g: &Vec>) -> bool {
- if i == destination {
- return true;
- }
- vis[i] = true;
- for &j in &g[i] {
- if !vis[j] && dfs(j, destination, vis, g) {
- return true;
+ fn dfs(g: &Vec>, vis: &mut Vec, i: usize, destination: usize) -> bool {
+ if i == destination {
+ return true;
+ }
+ vis[i] = true;
+ for &j in &g[i] {
+ if !vis[j] && dfs(g, vis, j, destination) {
+ return true;
+ }
+ }
+ false
}
+
+ dfs(&g, &mut vis, source, destination)
}
- false
}
```
@@ -262,15 +261,15 @@ fn dfs(i: usize, destination: usize, vis: &mut Vec, g: &Vec
### Solution 2: BFS
-We can also use BFS to determine whether there is a path from `source` to `destination`.
+We can also use BFS to determine whether there is a path from $\textit{source}$ to $\textit{destination}$.
-Specifically, we define a queue $q$ and initially add `source` to the queue. In addition, we use a set `vis` to record the vertices that have been visited to avoid repeated visits.
+Specifically, we define a queue $q$, initially adding $\textit{source}$ to the queue. Additionally, we use a set $\textit{vis}$ to record the vertices that have already been visited to avoid revisiting them.
-Next, we continuously take out the vertex $i$ from the queue. If $i = \textit{destination}$, it means that there is a path from `source` to `destination`, and we return `true`. Otherwise, we traverse all adjacent vertices $j$ of $i$. If $j$ has not been visited, we add $j$ to the queue $q$ and mark $j$ as visited.
+Next, we continuously take vertices $i$ from the queue. If $i = \textit{destination}$, it means there is a path from $\textit{source}$ to $\textit{destination}$, and we return $\textit{true}$. Otherwise, we traverse all adjacent vertices $j$ of $i$. If $j$ has not been visited, we add $j$ to the queue $q$ and mark $j$ as visited.
-Finally, if the queue is empty, it means that there is no path from `source` to `destination`, and we return `false`.
+Finally, if the queue is empty, it means there is no path from $\textit{source}$ to $\textit{destination}$, and we return $\textit{false}$.
-The time complexity is $O(n + m)$, and the space complexity is $O(n + m)$. Where $n$ and $m$ are the number of nodes and edges, respectively.
+The time complexity is $O(n + m)$, and the space complexity is $O(n + m)$. Here, $n$ and $m$ are the number of nodes and edges, respectively.
@@ -282,10 +281,9 @@ class Solution:
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
g = [[] for _ in range(n)]
- for a, b in edges:
- g[a].append(b)
- g[b].append(a)
-
+ for u, v in edges:
+ g[u].append(v)
+ g[v].append(u)
q = deque([source])
vis = {source}
while q:
@@ -307,9 +305,9 @@ class Solution {
List[] g = new List[n];
Arrays.setAll(g, k -> new ArrayList<>());
for (var e : edges) {
- int a = e[0], b = e[1];
- g[a].add(b);
- g[b].add(a);
+ int u = e[0], v = e[1];
+ g[u].add(v);
+ g[v].add(u);
}
Deque q = new ArrayDeque<>();
q.offer(source);
@@ -339,10 +337,10 @@ class Solution {
public:
bool validPath(int n, vector>& edges, int source, int destination) {
vector> g(n);
- for (auto& e : edges) {
- int a = e[0], b = e[1];
- g[a].push_back(b);
- g[b].push_back(a);
+ for (const auto& e : edges) {
+ int u = e[0], v = e[1];
+ g[u].push_back(v);
+ g[v].push_back(u);
}
queue q{{source}};
vector vis(n);
@@ -371,9 +369,9 @@ public:
func validPath(n int, edges [][]int, source int, destination int) bool {
g := make([][]int, n)
for _, e := range edges {
- a, b := e[0], e[1]
- g[a] = append(g[a], b)
- g[b] = append(g[b], a)
+ u, v := e[0], e[1]
+ g[u] = append(g[u], v)
+ g[v] = append(g[v], u)
}
q := []int{source}
vis := make([]bool, n)
@@ -400,27 +398,24 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
```ts
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
const g: number[][] = Array.from({ length: n }, () => []);
-
- for (const [a, b] of edges) {
- g[a].push(b);
- g[b].push(a);
+ for (const [u, v] of edges) {
+ g[u].push(v);
+ g[v].push(u);
}
-
- const vis = new Set();
+ const vis = new Set([source]);
const q = [source];
-
while (q.length) {
const i = q.pop()!;
if (i === destination) {
return true;
}
- if (vis.has(i)) {
- continue;
+ for (const j of g[i]) {
+ if (!vis.has(j)) {
+ vis.add(j);
+ q.push(j);
+ }
}
- vis.add(i);
- q.push(...g[i]);
}
-
return false;
}
```
@@ -432,26 +427,30 @@ use std::collections::{HashSet, VecDeque};
impl Solution {
pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
- let mut g = vec![HashSet::new(); n as usize];
- for e in edges {
- let a = e[0] as usize;
- let b = e[1] as usize;
- g[a].insert(b);
- g[b].insert(a);
+ let n = n as usize;
+ let source = source as usize;
+ let destination = destination as usize;
+
+ let mut g = vec![Vec::new(); n];
+ for edge in edges {
+ let u = edge[0] as usize;
+ let v = edge[1] as usize;
+ g[u].push(v);
+ g[v].push(u);
}
let mut q = VecDeque::new();
- q.push_back(source as usize);
- let mut vis = vec![false; n as usize];
- vis[source as usize] = true;
+ let mut vis = HashSet::new();
+ q.push_back(source);
+ vis.insert(source);
while let Some(i) = q.pop_front() {
- if i == (destination as usize) {
+ if i == destination {
return true;
}
for &j in &g[i] {
- if !vis[j] {
- vis[j] = true;
+ if !vis.contains(&j) {
+ vis.insert(j);
q.push_back(j);
}
}
@@ -484,65 +483,130 @@ The time complexity is $O(n \log n + m)$ or $O(n \alpha(n) + m)$, and the space
#### Python3
```python
+class UnionFind:
+ def __init__(self, n):
+ self.p = list(range(n))
+ self.size = [1] * n
+
+ def find(self, x):
+ if self.p[x] != x:
+ self.p[x] = self.find(self.p[x])
+ return self.p[x]
+
+ def union(self, a, b):
+ pa, pb = self.find(a), self.find(b)
+ if pa == pb:
+ return False
+ if self.size[pa] > self.size[pb]:
+ self.p[pb] = pa
+ self.size[pa] += self.size[pb]
+ else:
+ self.p[pa] = pb
+ self.size[pb] += self.size[pa]
+ return True
+
+
class Solution:
def validPath(
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
- def find(x):
- if p[x] != x:
- p[x] = find(p[x])
- return p[x]
-
- p = list(range(n))
+ uf = UnionFind(n)
for u, v in edges:
- p[find(u)] = find(v)
- return find(source) == find(destination)
+ uf.union(u, v)
+ return uf.find(source) == uf.find(destination)
```
#### Java
```java
-class Solution {
+class UnionFind {
private int[] p;
+ private int[] size;
- public boolean validPath(int n, int[][] edges, int source, int destination) {
+ public UnionFind(int n) {
p = new int[n];
+ size = new int[n];
for (int i = 0; i < n; ++i) {
p[i] = i;
+ size[i] = 1;
}
- for (int[] e : edges) {
- p[find(e[0])] = find(e[1]);
- }
- return find(source) == find(destination);
}
- private int find(int x) {
+ public int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
+
+ public void union(int a, int b) {
+ int pa = find(a), pb = find(b);
+ if (pa != pb) {
+ if (size[pa] > size[pb]) {
+ p[pb] = pa;
+ size[pa] += size[pb];
+ } else {
+ p[pa] = pb;
+ size[pb] += size[pa];
+ }
+ }
+ }
+}
+
+class Solution {
+ public boolean validPath(int n, int[][] edges, int source, int destination) {
+ UnionFind uf = new UnionFind(n);
+ for (var e : edges) {
+ uf.union(e[0], e[1]);
+ }
+ return uf.find(source) == uf.find(destination);
+ }
}
```
#### C++
```cpp
-class Solution {
+class UnionFind {
public:
- bool validPath(int n, vector>& edges, int source, int destination) {
- vector p(n);
+ UnionFind(int n) {
+ p = vector(n);
+ size = vector(n, 1);
iota(p.begin(), p.end(), 0);
- function find = [&](int x) -> int {
- if (p[x] != x) {
- p[x] = find(p[x]);
+ }
+
+ void unite(int a, int b) {
+ int pa = find(a), pb = find(b);
+ if (pa != pb) {
+ if (size[pa] > size[pb]) {
+ p[pb] = pa;
+ size[pa] += size[pb];
+ } else {
+ p[pa] = pb;
+ size[pb] += size[pa];
}
- return p[x];
- };
- for (auto& e : edges) {
- p[find(e[0])] = find(e[1]);
}
- return find(source) == find(destination);
+ }
+
+ int find(int x) {
+ if (p[x] != x) {
+ p[x] = find(p[x]);
+ }
+ return p[x];
+ }
+
+private:
+ vector p, size;
+};
+
+class Solution {
+public:
+ bool validPath(int n, vector>& edges, int source, int destination) {
+ UnionFind uf(n);
+ for (const auto& e : edges) {
+ uf.unite(e[0], e[1]);
+ }
+ return uf.find(source) == uf.find(destination);
}
};
```
@@ -550,40 +614,144 @@ public:
#### Go
```go
-func validPath(n int, edges [][]int, source int, destination int) bool {
+type unionFind struct {
+ p, size []int
+}
+
+func newUnionFind(n int) *unionFind {
p := make([]int, n)
+ size := make([]int, n)
for i := range p {
p[i] = i
+ size[i] = 1
}
- var find func(x int) int
- find = func(x int) int {
- if p[x] != x {
- p[x] = find(p[x])
- }
- return p[x]
+ return &unionFind{p, size}
+}
+
+func (uf *unionFind) find(x int) int {
+ if uf.p[x] != x {
+ uf.p[x] = uf.find(uf.p[x])
+ }
+ return uf.p[x]
+}
+
+func (uf *unionFind) union(a, b int) bool {
+ pa, pb := uf.find(a), uf.find(b)
+ if pa == pb {
+ return false
}
+ if uf.size[pa] > uf.size[pb] {
+ uf.p[pb] = pa
+ uf.size[pa] += uf.size[pb]
+ } else {
+ uf.p[pa] = pb
+ uf.size[pb] += uf.size[pa]
+ }
+ return true
+}
+
+func validPath(n int, edges [][]int, source int, destination int) bool {
+ uf := newUnionFind(n)
for _, e := range edges {
- p[find(e[0])] = find(e[1])
+ uf.union(e[0], e[1])
}
- return find(source) == find(destination)
+ return uf.find(source) == uf.find(destination)
}
```
#### TypeScript
```ts
+class UnionFind {
+ p: number[];
+ size: number[];
+ constructor(n: number) {
+ this.p = Array(n)
+ .fill(0)
+ .map((_, i) => i);
+ this.size = Array(n).fill(1);
+ }
+
+ find(x: number): number {
+ if (this.p[x] !== x) {
+ this.p[x] = this.find(this.p[x]);
+ }
+ return this.p[x];
+ }
+
+ union(a: number, b: number): boolean {
+ const [pa, pb] = [this.find(a), this.find(b)];
+ if (pa === pb) {
+ return false;
+ }
+ if (this.size[pa] > this.size[pb]) {
+ this.p[pb] = pa;
+ this.size[pa] += this.size[pb];
+ } else {
+ this.p[pa] = pb;
+ this.size[pb] += this.size[pa];
+ }
+ return true;
+ }
+}
+
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
- const p: number[] = Array.from({ length: n }, (_, i) => i);
- const find = (x: number): number => {
- if (p[x] !== x) {
- p[x] = find(p[x]);
+ const uf = new UnionFind(n);
+ edges.forEach(([u, v]) => uf.union(u, v));
+ return uf.find(source) === uf.find(destination);
+}
+```
+
+#### Rust
+
+```rust
+struct UnionFind {
+ p: Vec,
+ size: Vec,
+}
+
+impl UnionFind {
+ fn new(n: usize) -> Self {
+ let p = (0..n).collect();
+ let size = vec![1; n];
+ UnionFind { p, size }
+ }
+
+ fn find(&mut self, x: usize) -> usize {
+ if self.p[x] != x {
+ self.p[x] = self.find(self.p[x]);
}
- return p[x];
- };
- for (const [a, b] of edges) {
- p[find(a)] = find(b);
+ self.p[x]
+ }
+
+ fn union(&mut self, a: usize, b: usize) {
+ let pa = self.find(a);
+ let pb = self.find(b);
+ if pa != pb {
+ if self.size[pa] > self.size[pb] {
+ self.p[pb] = pa;
+ self.size[pa] += self.size[pb];
+ } else {
+ self.p[pa] = pb;
+ self.size[pb] += self.size[pa];
+ }
+ }
+ }
+}
+
+impl Solution {
+ pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
+ let n = n as usize;
+ let mut uf = UnionFind::new(n);
+
+ for e in edges {
+ let u = e[0] as usize;
+ let v = e[1] as usize;
+ uf.union(u, v);
+ }
+
+ uf.find(source as usize) == uf.find(destination as usize)
}
- return find(source) === find(destination);
}
```
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.cpp b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.cpp
index af46f0849ea14..2410b6e73b964 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.cpp
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.cpp
@@ -1,19 +1,19 @@
class Solution {
public:
bool validPath(int n, vector>& edges, int source, int destination) {
- vector vis(n);
vector g[n];
- for (auto& e : edges) {
- int a = e[0], b = e[1];
- g[a].emplace_back(b);
- g[b].emplace_back(a);
+ vector vis(n);
+ for (const auto& e : edges) {
+ int u = e[0], v = e[1];
+ g[u].push_back(v);
+ g[v].push_back(u);
}
function dfs = [&](int i) -> bool {
if (i == destination) {
return true;
}
vis[i] = true;
- for (int& j : g[i]) {
+ for (int j : g[i]) {
if (!vis[j] && dfs(j)) {
return true;
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.go b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.go
index 390abc8e8b690..00da71c43f56e 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.go
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.go
@@ -2,9 +2,9 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
vis := make([]bool, n)
g := make([][]int, n)
for _, e := range edges {
- a, b := e[0], e[1]
- g[a] = append(g[a], b)
- g[b] = append(g[b], a)
+ u, v := e[0], e[1]
+ g[u] = append(g[u], v)
+ g[v] = append(g[v], u)
}
var dfs func(int) bool
dfs = func(i int) bool {
@@ -20,4 +20,4 @@ func validPath(n int, edges [][]int, source int, destination int) bool {
return false
}
return dfs(source)
-}
\ No newline at end of file
+}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.java b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.java
index 82f9d740fbbe7..99cc3052bfb9f 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.java
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.java
@@ -4,15 +4,15 @@ class Solution {
private List[] g;
public boolean validPath(int n, int[][] edges, int source, int destination) {
+ this.destination = destination;
+ vis = new boolean[n];
g = new List[n];
- Arrays.setAll(g, k -> new ArrayList<>());
+ Arrays.setAll(g, i -> new ArrayList<>());
for (var e : edges) {
- int a = e[0], b = e[1];
- g[a].add(b);
- g[b].add(a);
+ int u = e[0], v = e[1];
+ g[u].add(v);
+ g[v].add(u);
}
- vis = new boolean[n];
- this.destination = destination;
return dfs(source);
}
@@ -21,7 +21,7 @@ private boolean dfs(int i) {
return true;
}
vis[i] = true;
- for (int j : g[i]) {
+ for (var j : g[i]) {
if (!vis[j] && dfs(j)) {
return true;
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.py b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.py
index be95b5cd3e82e..c40cb923ee69d 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.py
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.py
@@ -2,18 +2,16 @@ class Solution:
def validPath(
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
- def dfs(i):
+ def dfs(i: int) -> bool:
if i == destination:
return True
- vis.add(i)
- for j in g[i]:
- if j not in vis and dfs(j):
- return True
- return False
+ if i in vis:
+ return False
+ return any(dfs(j) for j in g[i])
g = [[] for _ in range(n)]
- for a, b in edges:
- g[a].append(b)
- g[b].append(a)
+ for u, v in edges:
+ g[u].append(v)
+ g[v].append(u)
vis = set()
return dfs(source)
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.rs b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.rs
index 4b4a4dce68760..d2dca838da612 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.rs
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.rs
@@ -1,28 +1,32 @@
impl Solution {
pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
- let mut disjoint_set: Vec = vec![0; n as usize];
- // Initialize the set
- for i in 0..n {
- disjoint_set[i as usize] = i;
- }
-
- // Traverse the edges
- for p_vec in &edges {
- let parent_one = Solution::find(p_vec[0], &mut disjoint_set);
- let parent_two = Solution::find(p_vec[1], &mut disjoint_set);
- disjoint_set[parent_one as usize] = parent_two;
- }
+ let n = n as usize;
+ let source = source as usize;
+ let destination = destination as usize;
- let p_s = Solution::find(source, &mut disjoint_set);
- let p_d = Solution::find(destination, &mut disjoint_set);
+ let mut g = vec![Vec::new(); n];
+ let mut vis = vec![false; n];
- p_s == p_d
- }
+ for e in edges {
+ let u = e[0] as usize;
+ let v = e[1] as usize;
+ g[u].push(v);
+ g[v].push(u);
+ }
- pub fn find(x: i32, d_set: &mut Vec) -> i32 {
- if d_set[x as usize] != x {
- d_set[x as usize] = Solution::find(d_set[x as usize], d_set);
+ fn dfs(g: &Vec>, vis: &mut Vec, i: usize, destination: usize) -> bool {
+ if i == destination {
+ return true;
+ }
+ vis[i] = true;
+ for &j in &g[i] {
+ if !vis[j] && dfs(g, vis, j, destination) {
+ return true;
+ }
+ }
+ false
}
- d_set[x as usize]
+
+ dfs(&g, &mut vis, source, destination)
}
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.ts b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.ts
index 649dc030166ae..5d15d8a1f942e 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.ts
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution.ts
@@ -1,10 +1,9 @@
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
const g: number[][] = Array.from({ length: n }, () => []);
- for (const [a, b] of edges) {
- g[a].push(b);
- g[b].push(a);
+ for (const [u, v] of edges) {
+ g[u].push(v);
+ g[v].push(u);
}
-
const vis = new Set();
const dfs = (i: number) => {
if (i === destination) {
@@ -13,10 +12,8 @@ function validPath(n: number, edges: number[][], source: number, destination: nu
if (vis.has(i)) {
return false;
}
-
vis.add(i);
return g[i].some(dfs);
};
-
return dfs(source);
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.cpp b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.cpp
index c2c1b73efe227..a2bd484075bde 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.cpp
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.cpp
@@ -2,10 +2,10 @@ class Solution {
public:
bool validPath(int n, vector>& edges, int source, int destination) {
vector> g(n);
- for (auto& e : edges) {
- int a = e[0], b = e[1];
- g[a].push_back(b);
- g[b].push_back(a);
+ for (const auto& e : edges) {
+ int u = e[0], v = e[1];
+ g[u].push_back(v);
+ g[v].push_back(u);
}
queue q{{source}};
vector vis(n);
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.go b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.go
index 6f3ca4c47530a..41ec9b817d41e 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.go
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.go
@@ -1,9 +1,9 @@
func validPath(n int, edges [][]int, source int, destination int) bool {
g := make([][]int, n)
for _, e := range edges {
- a, b := e[0], e[1]
- g[a] = append(g[a], b)
- g[b] = append(g[b], a)
+ u, v := e[0], e[1]
+ g[u] = append(g[u], v)
+ g[v] = append(g[v], u)
}
q := []int{source}
vis := make([]bool, n)
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.java b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.java
index f7f993924cc77..a1b0020870fcf 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.java
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.java
@@ -3,9 +3,9 @@ public boolean validPath(int n, int[][] edges, int source, int destination) {
List[] g = new List[n];
Arrays.setAll(g, k -> new ArrayList<>());
for (var e : edges) {
- int a = e[0], b = e[1];
- g[a].add(b);
- g[b].add(a);
+ int u = e[0], v = e[1];
+ g[u].add(v);
+ g[v].add(u);
}
Deque q = new ArrayDeque<>();
q.offer(source);
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.py b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.py
index 539791f3fc81e..6f8b5c7f461b3 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.py
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.py
@@ -3,10 +3,9 @@ def validPath(
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
g = [[] for _ in range(n)]
- for a, b in edges:
- g[a].append(b)
- g[b].append(a)
-
+ for u, v in edges:
+ g[u].append(v)
+ g[v].append(u)
q = deque([source])
vis = {source}
while q:
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.rs b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.rs
index 575018a990fce..d4509771b6b12 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.rs
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.rs
@@ -2,26 +2,30 @@ use std::collections::{HashSet, VecDeque};
impl Solution {
pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
- let mut g = vec![HashSet::new(); n as usize];
- for e in edges {
- let a = e[0] as usize;
- let b = e[1] as usize;
- g[a].insert(b);
- g[b].insert(a);
+ let n = n as usize;
+ let source = source as usize;
+ let destination = destination as usize;
+
+ let mut g = vec![Vec::new(); n];
+ for edge in edges {
+ let u = edge[0] as usize;
+ let v = edge[1] as usize;
+ g[u].push(v);
+ g[v].push(u);
}
let mut q = VecDeque::new();
- q.push_back(source as usize);
- let mut vis = vec![false; n as usize];
- vis[source as usize] = true;
+ let mut vis = HashSet::new();
+ q.push_back(source);
+ vis.insert(source);
while let Some(i) = q.pop_front() {
- if i == (destination as usize) {
+ if i == destination {
return true;
}
for &j in &g[i] {
- if !vis[j] {
- vis[j] = true;
+ if !vis.contains(&j) {
+ vis.insert(j);
q.push_back(j);
}
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.ts b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.ts
index 1d741f6bb04f2..11947531475d0 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.ts
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution2.ts
@@ -1,25 +1,22 @@
function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
const g: number[][] = Array.from({ length: n }, () => []);
-
- for (const [a, b] of edges) {
- g[a].push(b);
- g[b].push(a);
+ for (const [u, v] of edges) {
+ g[u].push(v);
+ g[v].push(u);
}
-
- const vis = new Set();
+ const vis = new Set([source]);
const q = [source];
-
while (q.length) {
const i = q.pop()!;
if (i === destination) {
return true;
}
- if (vis.has(i)) {
- continue;
+ for (const j of g[i]) {
+ if (!vis.has(j)) {
+ vis.add(j);
+ q.push(j);
+ }
}
- vis.add(i);
- q.push(...g[i]);
}
-
return false;
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.cpp b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.cpp
index a84222dead5ea..adc9bcae5a731 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.cpp
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.cpp
@@ -1,17 +1,42 @@
-class Solution {
+class UnionFind {
public:
- bool validPath(int n, vector>& edges, int source, int destination) {
- vector p(n);
+ UnionFind(int n) {
+ p = vector(n);
+ size = vector(n, 1);
iota(p.begin(), p.end(), 0);
- function find = [&](int x) -> int {
- if (p[x] != x) {
- p[x] = find(p[x]);
+ }
+
+ void unite(int a, int b) {
+ int pa = find(a), pb = find(b);
+ if (pa != pb) {
+ if (size[pa] > size[pb]) {
+ p[pb] = pa;
+ size[pa] += size[pb];
+ } else {
+ p[pa] = pb;
+ size[pb] += size[pa];
}
- return p[x];
- };
- for (auto& e : edges) {
- p[find(e[0])] = find(e[1]);
}
- return find(source) == find(destination);
+ }
+
+ int find(int x) {
+ if (p[x] != x) {
+ p[x] = find(p[x]);
+ }
+ return p[x];
+ }
+
+private:
+ vector p, size;
+};
+
+class Solution {
+public:
+ bool validPath(int n, vector>& edges, int source, int destination) {
+ UnionFind uf(n);
+ for (const auto& e : edges) {
+ uf.unite(e[0], e[1]);
+ }
+ return uf.find(source) == uf.find(destination);
}
};
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.go b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.go
index 9f30955e375de..22bef71b22a6a 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.go
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.go
@@ -1,17 +1,43 @@
-func validPath(n int, edges [][]int, source int, destination int) bool {
+type unionFind struct {
+ p, size []int
+}
+
+func newUnionFind(n int) *unionFind {
p := make([]int, n)
+ size := make([]int, n)
for i := range p {
p[i] = i
+ size[i] = 1
+ }
+ return &unionFind{p, size}
+}
+
+func (uf *unionFind) find(x int) int {
+ if uf.p[x] != x {
+ uf.p[x] = uf.find(uf.p[x])
}
- var find func(x int) int
- find = func(x int) int {
- if p[x] != x {
- p[x] = find(p[x])
- }
- return p[x]
+ return uf.p[x]
+}
+
+func (uf *unionFind) union(a, b int) bool {
+ pa, pb := uf.find(a), uf.find(b)
+ if pa == pb {
+ return false
+ }
+ if uf.size[pa] > uf.size[pb] {
+ uf.p[pb] = pa
+ uf.size[pa] += uf.size[pb]
+ } else {
+ uf.p[pa] = pb
+ uf.size[pb] += uf.size[pa]
}
+ return true
+}
+
+func validPath(n int, edges [][]int, source int, destination int) bool {
+ uf := newUnionFind(n)
for _, e := range edges {
- p[find(e[0])] = find(e[1])
+ uf.union(e[0], e[1])
}
- return find(source) == find(destination)
+ return uf.find(source) == uf.find(destination)
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.java b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.java
index 640d32b33bba7..95d53f311390d 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.java
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.java
@@ -1,21 +1,43 @@
-class Solution {
+class UnionFind {
private int[] p;
+ private int[] size;
- public boolean validPath(int n, int[][] edges, int source, int destination) {
+ public UnionFind(int n) {
p = new int[n];
+ size = new int[n];
for (int i = 0; i < n; ++i) {
p[i] = i;
+ size[i] = 1;
}
- for (int[] e : edges) {
- p[find(e[0])] = find(e[1]);
- }
- return find(source) == find(destination);
}
- private int find(int x) {
+ public int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
+
+ public void union(int a, int b) {
+ int pa = find(a), pb = find(b);
+ if (pa != pb) {
+ if (size[pa] > size[pb]) {
+ p[pb] = pa;
+ size[pa] += size[pb];
+ } else {
+ p[pa] = pb;
+ size[pb] += size[pa];
+ }
+ }
+ }
+}
+
+class Solution {
+ public boolean validPath(int n, int[][] edges, int source, int destination) {
+ UnionFind uf = new UnionFind(n);
+ for (var e : edges) {
+ uf.union(e[0], e[1]);
+ }
+ return uf.find(source) == uf.find(destination);
+ }
}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.py b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.py
index a6d19f52c4fcd..f46da38331785 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.py
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.py
@@ -1,13 +1,31 @@
+class UnionFind:
+ def __init__(self, n):
+ self.p = list(range(n))
+ self.size = [1] * n
+
+ def find(self, x):
+ if self.p[x] != x:
+ self.p[x] = self.find(self.p[x])
+ return self.p[x]
+
+ def union(self, a, b):
+ pa, pb = self.find(a), self.find(b)
+ if pa == pb:
+ return False
+ if self.size[pa] > self.size[pb]:
+ self.p[pb] = pa
+ self.size[pa] += self.size[pb]
+ else:
+ self.p[pa] = pb
+ self.size[pb] += self.size[pa]
+ return True
+
+
class Solution:
def validPath(
self, n: int, edges: List[List[int]], source: int, destination: int
) -> bool:
- def find(x):
- if p[x] != x:
- p[x] = find(p[x])
- return p[x]
-
- p = list(range(n))
+ uf = UnionFind(n)
for u, v in edges:
- p[find(u)] = find(v)
- return find(source) == find(destination)
+ uf.union(u, v)
+ return uf.find(source) == uf.find(destination)
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.rs b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.rs
new file mode 100644
index 0000000000000..8656cd2b90b5f
--- /dev/null
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.rs
@@ -0,0 +1,48 @@
+struct UnionFind {
+ p: Vec,
+ size: Vec,
+}
+
+impl UnionFind {
+ fn new(n: usize) -> Self {
+ let p = (0..n).collect();
+ let size = vec![1; n];
+ UnionFind { p, size }
+ }
+
+ fn find(&mut self, x: usize) -> usize {
+ if self.p[x] != x {
+ self.p[x] = self.find(self.p[x]);
+ }
+ self.p[x]
+ }
+
+ fn union(&mut self, a: usize, b: usize) {
+ let pa = self.find(a);
+ let pb = self.find(b);
+ if pa != pb {
+ if self.size[pa] > self.size[pb] {
+ self.p[pb] = pa;
+ self.size[pa] += self.size[pb];
+ } else {
+ self.p[pa] = pb;
+ self.size[pb] += self.size[pa];
+ }
+ }
+ }
+}
+
+impl Solution {
+ pub fn valid_path(n: i32, edges: Vec>, source: i32, destination: i32) -> bool {
+ let n = n as usize;
+ let mut uf = UnionFind::new(n);
+
+ for e in edges {
+ let u = e[0] as usize;
+ let v = e[1] as usize;
+ uf.union(u, v);
+ }
+
+ uf.find(source as usize) == uf.find(destination as usize)
+ }
+}
diff --git a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.ts b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.ts
index 76c3c8e38adc6..1b99f50f1b18f 100644
--- a/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.ts
+++ b/solution/1900-1999/1971.Find if Path Exists in Graph/Solution3.ts
@@ -1,13 +1,38 @@
-function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
- const p: number[] = Array.from({ length: n }, (_, i) => i);
- const find = (x: number): number => {
- if (p[x] !== x) {
- p[x] = find(p[x]);
+class UnionFind {
+ p: number[];
+ size: number[];
+ constructor(n: number) {
+ this.p = Array(n)
+ .fill(0)
+ .map((_, i) => i);
+ this.size = Array(n).fill(1);
+ }
+
+ find(x: number): number {
+ if (this.p[x] !== x) {
+ this.p[x] = this.find(this.p[x]);
}
- return p[x];
- };
- for (const [a, b] of edges) {
- p[find(a)] = find(b);
+ return this.p[x];
}
- return find(source) === find(destination);
+
+ union(a: number, b: number): boolean {
+ const [pa, pb] = [this.find(a), this.find(b)];
+ if (pa === pb) {
+ return false;
+ }
+ if (this.size[pa] > this.size[pb]) {
+ this.p[pb] = pa;
+ this.size[pa] += this.size[pb];
+ } else {
+ this.p[pa] = pb;
+ this.size[pb] += this.size[pa];
+ }
+ return true;
+ }
+}
+
+function validPath(n: number, edges: number[][], source: number, destination: number): boolean {
+ const uf = new UnionFind(n);
+ edges.forEach(([u, v]) => uf.union(u, v));
+ return uf.find(source) === uf.find(destination);
}