标签:leetcode course schedule 207
There are a total of n courses you have to take, labeled from 0 to n - 1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
查阅题目知:实际上是求一个图中是否存在环。可以考虑使用拓扑排序。
拓扑排序:
拓扑排序(Topological Order)是指,将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。
这样说,可能理解起来比较抽象。下面通过简单的例子进行说明!
例如,一个项目包括A、B、C、D四个子部分来完成,并且A依赖于B和D,C依赖于D。现在要制定一个计划,写出A、B、C、D的执行顺序。这时,就可以利用到拓扑排序,它就是用来确定事物发生的顺序的。
在拓扑排序中,如果存在一条从顶点A到顶点B的路径,那么在排序结果中B出现在A的后面。
拓扑排序算法的基本步骤:
1. 构造一个队列Q(queue) 和 拓扑排序的结果队列T(topological);
2. 把所有没有依赖顶点的节点放入Q;
3. 当Q还有顶点的时候,执行下面步骤:
3.1 从Q中取出一个顶点n(将n从Q中删掉),并放入T(将n加入到结果集中);
3.2 对n每一个邻接点m(n是起点,m是终点);
3.2.1 去掉边
public class Solution {
/*
* 拓扑排序
* 1. 选择入度为0的点
* 2. 将选中的点从图中去掉
*/
public boolean canFinish(int numCourses, int[][] prerequisites) {
//图使用邻接矩阵表示
int[][] E = new int[numCourses][numCourses];
//顶点的入度
long[] degree = new long[numCourses];
if(numCourses <= 1 ){
return true;
}
//构造图矩阵
//E[i][j]表示i的前驱是j
for(int i = 0 ; i < prerequisites.length ; i ++){
E[prerequisites[i][0]][prerequisites[i][1]] = 1;
degree[prerequisites[i][1]] ++;
}
//初始化入度
for(int j = 0;j < numCourses; j ++){
for(int i = 0; i < numCourses;i++){
if(E[i][j] == 1){
degree[j] ++;
}
}
}
//判断
while(true){
int var = select0(degree);
if(var > -1){
delete0(var,E,degree);
}else{
break;
}
}
for(int i = 0; i < degree.length;i ++){
if(degree[i] != Long.MAX_VALUE){
return false;
}
}
return true;
}
//选择入度为0
public int select0(long[] degree){
for(int i = 0; i < degree.length;i++){
if(degree[i] == 0){
//degree[i] = Long.MAX_VALUE;
return i;
}
}
return -1;
}
//将点从图中去掉
public void delete0(int var, int[][] E,long[] degree){
degree[var] = Long.MAX_VALUE;
for(int j = 0; j < E.length;j++){
if(E[var][j] == 1){
degree[j]--;
}
}
}
}
尝试之后显示Status: Time Limit Exceeded
参阅网上的解法,显然都是用拓扑排序的思想,那么自己的程序速度在哪慢了?
//构造图矩阵
//E[i][j]表示i的前驱是j
for(int i = 0 ; i < prerequisites.length ; i ++){
E[prerequisites[i][0]][prerequisites[i][1]] = 1;
degree[prerequisites[i][1]] ++;
}
//初始化入度
for(int j = 0;j < numCourses; j ++){
for(int i = 0; i < numCourses;i++){
if(E[i][j] == 1){
degree[j] ++;
}
}
}
显然在构造邻接矩阵的时候就可以构造出入度数组,如
for(int i = 0 ; i < prerequisites.length ; i ++){
if(E[prerequisites[i][0]][prerequisites[i][1]] == 0){
E[prerequisites[i][0]][prerequisites[i][1]] = 1;
degree[prerequisites[i][1]] ++;
}
}
需要注意的是:prerequisite[i][j]可能会出现相同的序列对,如{{5,8},{3,5},{1,9},{4,5},{0,2},{1,9},{7,8},{4,9}};
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:leetcode course schedule 207
原文地址:http://blog.csdn.net/havedream_one/article/details/47004543