方法一 深度优先遍历
第一步,使用邻接表构建有向图
List<List<Integer>> adjacency = new ArrayList<>();
//必须为每个表项创建空List,否则dfs里遍历邻接表会抛出越界异常
//注意题目要求,你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1
for(int i = 0; i < numCourses; i++){
adjacency.add(new ArrayList<>());
}
for(int[] pair : prerequisites){
adjacency.get(pair[1]).add(pair[0]);
}
第二步,使用flags数组对图节点进行标记,0表示未遍历过该节点,1表示当前dfs已经遍历过该节点,-1表示过去的dfs已经遍历过该节点
第三步,构建dfs
private boolean dfs(List<List<Integer>> adjacency, int[] flags, int courseIndex) {
if (flags[courseIndex] == 1) {
return false;
}
if (flags[courseIndex] == -1) {
return true;
}
flags[courseIndex] = 1;
for (int nextCourse : adjacency.get(courseIndex)) {
if (!dfs(adjacency, flags, nextCourse)) {
return false;
}
}
flags[courseIndex] = -1;
return true;
}
递归出口
- 如果当前节点的
flag == 1,说明有向图存在环,直接return false - 如果当前节点的
flag == -1,说明该节点在之前的dfs已经遍历过,无需继续遍历
递归前将当前节点标记为1
使用for循环依次取出当前节点邻接表里的节点,继续dfs
递归后,因为return true,将当前节点标记为-1
第四步,使用for循环从有向图里每个节点开始dfs
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<List<Integer>> adjacency = new ArrayList<>();
for(int i = 0; i < numCourses; i++){
adjacency.add(new ArrayList<>());
}
for(int[] pair : prerequisites){
adjacency.get(pair[1]).add(pair[0]);
}
int[] flags = new int[numCourses];
for(int i = 0; i < numCourses; i++){
if(!dfs(adjacency, flags, i)){
return false;
}
}
return true;
}
private boolean dfs(List<List<Integer>> adjacency, int[] flags, int courseIndex) {
if (flags[courseIndex] == 1) {
return false;
}
if (flags[courseIndex] == -1) {
return true;
}
flags[courseIndex] = 1;
for (int nextCourse : adjacency.get(courseIndex)) {
if (!dfs(adjacency, flags, nextCourse)) {
return false;
}
}
flags[courseIndex] = -1;
return true;
}
}
方法二 广度优先遍历(算法复杂,不推荐)
算法思路
总的来说,就是看能不能把所有节点的入度变成0
- 首先构建好邻接表和入度表
- 入度为
0的节点入队列 - 从队列中取出一个入度为
0的节点,总节点数量-1,将该节点的邻接节点,对应入度表的入度-1,如果该节点入度变为0,则入队 - 循环该操作,如果总节点数量
== 0,则没有环
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<List<Integer>> adjacency = new ArrayList<>();
for (int i = 0; i < numCourses; i++) {
adjacency.add(new ArrayList<>());
}
int[] indegree = new int[numCourses];
for (int[] pair : prerequisites) {
adjacency.get(pair[1]).add(pair[0]);
++indegree[pair[0]];
}
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) {
queue.offer(i);
}
}
while (!queue.isEmpty()) {
int pre = queue.poll();
numCourses--;
for (int next : adjacency.get(pre)) {
if (--indegree[next] == 0) {
queue.offer(next);
}
}
}
return numCourses == 0;
}
}