以图判树
难度:
标签:
题目描述
代码结果
运行时间: 18 ms, 内存: 17.2 MB
/*
* 使用Java Stream的题解代码和注释
* 题目:以图判树
* 解题思路:
* 1. 如果图的边数不等于节点数减一,则直接返回false。
* 2. 使用Union-Find数据结构检查是否存在环。
* 3. 检查图的连通性。
*/
import java.util.stream.IntStream;
public class Solution {
public boolean validTree(int n, int[][] edges) {
if (edges.length != n - 1) return false;
int[] parent = IntStream.range(0, n).toArray();
for (int[] edge : edges) {
int root1 = find(parent, edge[0]);
int root2 = find(parent, edge[1]);
if (root1 == root2) return false;
parent[root1] = root2;
}
return true;
}
private int find(int[] parent, int p) {
while (p != parent[p]) {
parent[p] = parent[parent[p]]; // 路径压缩
p = parent[p];
}
return p;
}
}
解释
方法:
该题解使用了并查集来判断给定的边集是否构成一棵树。并查集是一种树形数据结构,用于处理不相交集合的合并及查询所属集合等操作。通过并查集,我们可以高效地判断图中是否存在环以及连通分量的个数。
具体思路如下:
1. 首先,树中边的数量必须等于节点数减一,否则一定不是树。
2. 接着,初始化一个大小为 n 的并查集,每个节点各自为一个集合。
3. 遍历所有的边,对于每条边 (A, B),找到 A 和 B 所在集合的根节点。
- 如果 A 和 B 在同一个集合中,说明出现了环,不是树,返回 false。
- 如果 A 和 B 不在同一个集合中,则将它们所在的集合合并为一个集合。
4. 遍历完所有的边后,如果没有出现环,说明是一棵树,返回 true。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在并查集的实现中,为什么选择了未优化的 find 和 union 方法,而没有使用路径压缩或按秩合并这些常用的优化技术?
▷🦆
代码中提到如果两个节点已在同一个集合中则表示存在环,这种方法是否能准确处理所有图的情况,即使图是非连通的?
▷🦆
在判断一棵树的定义时,除了检查边的数量等于节点数减一,还需要考虑什么条件以确保结构确实是一棵树?
▷🦆
解法中提到如果边的数量不等于节点数减一就直接返回false,这种做法是否考虑了所有可能的非树结构情况?
▷相关问题
课程表
你这个学期必须选修 numCourses
门课程,记为 0
到 numCourses - 1
。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites
给出,其中 prerequisites[i] = [ai, bi]
,表示如果要学习课程 ai
则 必须 先学习课程 bi
。
- 例如,先修课程对
[0, 1]
表示:想要学习课程0
,你需要先完成课程1
。
请你判断是否可能完成所有课程的学习?如果可以,返回 true
;否则,返回 false
。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]] 输出:true 解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]] 输出:false 解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i]
中的所有课程对 互不相同