Skip to content

feat: add solutions to lc problem: No.261 #2603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 191 additions & 34 deletions solution/0200-0299/0261.Graph Valid Tree/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,33 @@

## 解法

### 方法一
### 方法一:并查集

判断是否是树,需要满足以下两个条件:

1. 边的数量等于节点数减一;
2. 不存在环。

我们可以使用并查集来判断是否存在环。遍历边,如果两个节点已经在同一个集合中,说明存在环。否则,我们将两个节点合并到同一个集合中。然后将连通分量的数量减一,最后判断连通分量的数量是否为 $1$。

时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是节点数。

<!-- tabs:start -->

```python
class Solution:
def validTree(self, n: int, edges: List[List[int]]) -> bool:
def find(x):
def find(x: int) -> int:
if p[x] != x:
p[x] = find(p[x])
return p[x]

p = list(range(n))
for a, b in edges:
if find(a) == find(b):
pa, pb = find(a), find(b)
if pa == pb:
return False
p[find(a)] = find(b)
p[pa] = pb
n -= 1
return n == 1
```
Expand All @@ -75,12 +85,12 @@ class Solution {
for (int i = 0; i < n; ++i) {
p[i] = i;
}
for (int[] e : edges) {
int a = e[0], b = e[1];
if (find(a) == find(b)) {
for (var e : edges) {
int pa = find(e[0]), pb = find(e[1]);
if (pa == pb) {
return false;
}
p[find(a)] = find(b);
p[pa] = pb;
--n;
}
return n == 1;
Expand All @@ -98,24 +108,25 @@ class Solution {
```cpp
class Solution {
public:
vector<int> p;

bool validTree(int n, vector<vector<int>>& edges) {
p.resize(n);
for (int i = 0; i < n; ++i) p[i] = i;
vector<int> p(n);
iota(p.begin(), p.end(), 0);
function<int(int)> find = [&](int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
};
for (auto& e : edges) {
int a = e[0], b = e[1];
if (find(a) == find(b)) return 0;
p[find(a)] = find(b);
int pa = find(e[0]), pb = find(e[1]);
if (pa == pb) {
return false;
}
p[pa] = pb;
--n;
}
return n == 1;
}

int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
};
```

Expand All @@ -125,19 +136,19 @@ func validTree(n int, edges [][]int) bool {
for i := range p {
p[i] = i
}
var find func(x int) int
var find func(int) int
find = func(x int) int {
if p[x] != x {
p[x] = find(p[x])
}
return p[x]
}
for _, e := range edges {
a, b := e[0], e[1]
if find(a) == find(b) {
pa, pb := find(e[0]), find(e[1])
if pa == pb {
return false
}
p[find(a)] = find(b)
p[pa] = pb
n--
}
return n == 1
Expand All @@ -151,24 +162,170 @@ func validTree(n int, edges [][]int) bool {
* @return {boolean}
*/
var validTree = function (n, edges) {
let p = new Array(n);
for (let i = 0; i < n; ++i) {
p[i] = i;
}
function find(x) {
if (p[x] != x) {
const p = Array.from({ length: n }, (_, i) => i);
const find = x => {
if (p[x] !== x) {
p[x] = find(p[x]);
}
return p[x];
}
};
for (const [a, b] of edges) {
if (find(a) == find(b)) {
const pa = find(a);
const pb = find(b);
if (pa === pb) {
return false;
}
p[find(a)] = find(b);
p[pa] = pb;
--n;
}
return n == 1;
return n === 1;
};
```

<!-- tabs:end -->

### 方法二:DFS

我们也可以使用深度优先搜索来判断是否存在环。我们可以使用一个数组 $vis$ 来记录访问过的节点,搜索时,我们先将节点标记为已访问,然后遍历与该节点相邻的节点,如果相邻节点已经访问过,则跳过,否则递归访问相邻节点。最后,我们判断是否所有节点都被访问过,如果有未访问过的节点,说明无法构成树,返回 `false`。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是节点数。

<!-- tabs:start -->

```python
class Solution:
def validTree(self, n: int, edges: List[List[int]]) -> bool:
def dfs(i: int):
vis.add(i)
for j in g[i]:
if j not in vis:
dfs(j)

if len(edges) != n - 1:
return False
g = [[] for _ in range(n)]
for a, b in edges:
g[a].append(b)
g[b].append(a)
vis = set()
dfs(0)
return len(vis) == n
```

```java
class Solution {
private List<Integer>[] g;
private Set<Integer> vis = new HashSet<>();

public boolean validTree(int n, int[][] edges) {
if (edges.length != n - 1) {
return false;
}
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);
}
dfs(0);
return vis.size() == n;
}

private void dfs(int i) {
vis.add(i);
for (int j : g[i]) {
if (!vis.contains(j)) {
dfs(j);
}
}
}
}
```

```cpp
class Solution {
public:
bool validTree(int n, vector<vector<int>>& edges) {
if (edges.size() != n - 1) {
return false;
}
vector<int> g[n];
vector<int> vis(n);
function<void(int)> dfs = [&](int i) {
vis[i] = true;
--n;
for (int j : g[i]) {
if (!vis[j]) {
dfs(j);
}
}
};
for (auto& e : edges) {
int a = e[0], b = e[1];
g[a].push_back(b);
g[b].push_back(a);
}
dfs(0);
return n == 0;
}
};
```

```go
func validTree(n int, edges [][]int) bool {
if len(edges) != n-1 {
return false
}
g := make([][]int, n)
vis := make([]bool, n)
for _, e := range edges {
a, b := e[0], e[1]
g[a] = append(g[a], b)
g[b] = append(g[b], a)
}
var dfs func(int)
dfs = func(i int) {
vis[i] = true
n--
for _, j := range g[i] {
if !vis[j] {
dfs(j)
}
}
}
dfs(0)
return n == 0
}
```

```js
/**
* @param {number} n
* @param {number[][]} edges
* @return {boolean}
*/
var validTree = function (n, edges) {
if (edges.length !== n - 1) {
return false;
}
const g = Array.from({ length: n }, () => []);
const vis = Array.from({ length: n }, () => false);
for (const [a, b] of edges) {
g[a].push(b);
g[b].push(a);
}
const dfs = i => {
vis[i] = true;
--n;
for (const j of g[i]) {
if (!vis[j]) {
dfs(j);
}
}
};
dfs(0);
return n === 0;
};
```

Expand Down
Loading