LeetCode -- Course Schedule

来源:互联网 发布:立项依据怎么写 知乎 编辑:程序博客网 时间:2024/04/24 08:45
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}};

0 0
原创粉丝点击