大家在上大学的时候,应该都遇到过这样的情况,有些高级的课程需要你先完成基础课程后才可以学习。在「图11. 课程关系图」中,如果你想选课程 C,那你需要先完成课程 B,如果你想选课程 B,那么你需要先完成课程 A。
此时,就需要「拓扑排序」的帮忙了。「拓扑排序」针对的是 有向无环图 的一种算法。它是对「图」中所有顶点按照先后顺序的一种线性排序。换句话说,在如果存在顶点 u 和顶点 v,要想到达顶点 v,则必须要到达顶点 u 。那么在「拓扑排序」中,顶点 u 必须处于顶点 v 的前面。
Khan算法的步骤如下:
- 创建一个degree数组用来记录每个点当前的入度,并将所有值初始化为0
- 遍历所有边,更新degree数组
- 创建队列
- 若队列不空,出队一个点,记录在排序数组中,将degree对应位置设为-1,找到所有由它出发可以直接到达的点,将这些点的degree全部减一。
- 遍历degree数组,将找到的第一个值为0的点入队。
- 当队列不空时循环45两步。
课程表 II
现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。
例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。
返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
为了提高效率,我们把边转化成邻接矩阵的形式存储。
public class Solution {
public int[] FindOrder(int numCourses, int[][] prerequisites) {
int[] res=new int[numCourses];
if(numCourses==1)
{
res[0]=0;
return res;
}
int[] degree=new int[numCourses];
bool[,] matrix=new bool[numCourses,numCourses];
for(int i=0;i<numCourses;i++)
{
degree[i]=0;
for(int j=0;j<numCourses;j++)
matrix[i,j]=false;
}
for(int i=0;i<prerequisites.Length;i++)
{
degree[prerequisites[i][0]]++;
matrix[prerequisites[i][1],prerequisites[i][0]]=true;
}
Queue<int> q=new Queue<int>();
int a=0;
do
{
if(q.Count!=0)
{
int degree0=q.Dequeue();
res[a++]=degree0;
degree[degree0]=-1;
for(int i=0;i<numCourses;i++)
if(matrix[degree0,i])
degree[i]--;
}
for(int i=0;i<numCourses;i++)
if(degree[i]==0)
{
q.Enqueue(i);
break;
}
}while(q.Count!=0);
if(a==numCourses)
return res;
else
{
int[] empty=new int[0];
return empty;
}
}
}