LeetCode:207. 课程表
拓扑排序(Kahn 算法,其实就是广度优先遍历的思路)
拓扑排序实际上应用的是贪心算法。贪心算法简而言之:每一步最优,全局就最优。
贪的点是:当前让入度为 0 的那些结点入队;
每一次都从图中删除没有前驱的顶点,这里并不需要真正的做删除操作,我们可以设置一个入度数组,每一轮都输出入度为 0 的结点,并移除它、修改它指向的结点的入度( -1 即可),依次得到的结点序列就是拓扑排序的结点序列。如果图中还有结点没有被移除,则说明“不能完成所有课程的学习”。
AC Code
class Solution {
public boolean canFinish(int numCourses, int[][] p) {
// 拓扑排序 - 广度优先遍历的思路
int[] inDegree = new int[numCourses];
HashSet<Integer>[] adj = new HashSet[numCourses];
for(int i = 0; i < numCourses; i++) adj[i] = new HashSet<>();
int len = p.length;
for(int i = 0; i < len; i++) {
inDegree[p[i][0]]++;
adj[p[i][1]].add(p[i][0]);
}
Queue<Integer> queue = new LinkedList<>();
// 首先加入入度为 0 的结点
for(int i = 0; i < numCourses; i++) {
if(inDegree[i] == 0) queue.add(i);
}
// 记录已经出队的课程数量
int cnt = 0;
while(!queue.isEmpty()) {
int num = queue.poll();
cnt++;
// 遍历当前出队结点的所有后继结点
for(Integer idx : adj[num]) {
inDegree[idx]--;
if(inDegree[idx] == 0) {
// 入度为 0 了
queue.add(idx);
}
}
}
// 移除掉的课程是否与总课程数相等
return cnt == numCourses;
}
}
参考: 拓扑排序、深度优先遍历