LeetCode原题
207. 课程表,链接: link
解题思路
- 1.深度优先遍历DFS
- 抽象构建成一个有向图(邻接表,或邻接矩阵)
- 遍历图中每个节点
- 判断有向图是否有环
- 2.广度优先遍历BFS。
- 抽象构建成一个有向图(邻接表,或邻接矩阵)
- 构建一个数组记录每个节点的入度
- 对 BFS 队列进行初始化,将入度为 0 的节点首先装入队列
- 开始执行 BFS 循环,不断弹出队列中的节点,减少相邻节点的入度,并将入度变为 0 的节点加入队列
- 如果最终所有节点都被遍历过(count 等于节点数),则说明不存在环,反之则说明存在环
代码
Java
class Solution {
// 思路1:DFS
// 记录遍历过的节点,防止走回头路
boolean[] visited;
// 记录一次递归堆栈中的节点
boolean[] onPath;
// 记录图中是否有环
boolean hasCycle = false;
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<Integer>[] graph = buildGraph(numCourses, prerequisites);
visited = new boolean[numCourses];
onPath = new boolean[numCourses];
for (int i = 0; i < numCourses; i++) {
traverse(graph, i);
}
return !hasCycle;
}
public void traverse(List<Integer>[] graph, int s) {
// base case
if (onPath[s]) {
hasCycle = true;
}
if (visited[s] || hasCycle) {
return;
}
visited[s] = true;
onPath[s] = true;
for (int t : graph[s]) {
traverse(graph, t);
}
onPath[s] = false;
}
public List<Integer>[] buildGraph(int numCourses, int[][] prerequisites) {
List<Integer>[] graph = new LinkedList[numCourses];
for (int i = 0; i < numCourses; i++) {
graph[i] = new LinkedList<>();
}
for (int[] edge : prerequisites) {
int from = edge[1], to = edge[0];
graph[from].add(to);
}
return graph;
}
}
注意要点
- 细节
- 抽象图(由节点和边组成,可看做是多叉树)类问题,选择合适的数据结构模型:邻接表(List[] graph;占用空间较少),或邻接矩阵(boolean[][] matrix;占用空间较多,便于直接判断两个节点是否相邻),可通过值来存储权值
- 遍历和访问(操作):设定visited、onPath数组,来判断是否成环
- 延伸
- 若是要获取图的拓扑排序,将后序遍历的结果进行反转,就是拓扑排序的结果
推荐相关
- 210 课程表 II
- 797 所有可能的路径
- 547 省份数量
- 785 判断二分图
- 210 课程表 II