Course Schedule && Course Schedule ||
For Course Schedule
Problem description: 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?
Example
Given n = 2, prerequisites = [[1,0]]
Return true
Given n = 2, prerequisites = [[1,0],[0,1]]
Return false
题目意思是说某些课程要上的话有先修课程的要求,比如要修Java web开发那么就需要修过java,某些学校的选课系统就有此限制。那么很显然这道题我们会想到结题思想就是拓扑排序(topological sort)。
拓扑排序对应施工的流程图具有特别重要的作用,它可以决定哪些子工程必须要先执行,哪些子工程要在某些工程执行后才可以执行。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。
一个AOV网应该是一个有向无环图,即不应该带有回路,因为若带有回路,则回路上的所有活动都无法进行(对于数据流来说就是死循环)。在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。
所以在此题中我们只需要构建出拓扑序列,判断是否具有环即可,如有环,则表示不能修完这些课程,若无环,则表示可以修完这些课程。先贴代码:
public boolean canFinish(int numCourses, int[][] prerequisites) {
// write your code here
int[] inDegree = new int[numCourses];
if(prerequisites == null || prerequisites.length == 0){
return true;
}
HashMap<Integer, List<Integer>> graph = new HashMap<Integer, List<Integer>>();
for(int i = 0; i < prerequisites.length; i++){
inDegree[prerequisites[i][0]]++;
if(graph.containsKey(prerequisites[i][1])){
graph.get(prerequisites[i][1]).add(prerequisites[i][0]);
}else{
ArrayList<Integer> list = new ArrayList();
list.add(prerequisites[i][0]);
graph.put(prerequisites[i][1], list);
}
}
LinkedList<Integer> queue = new LinkedList();
for(int i = 0; i < numCourses; i++){
if(inDegree[i] == 0){
queue.offer(i);
}
}
while(!queue.isEmpty()){
int course = queue.poll();
List<Integer> subcourses = graph.get(course);
for(int i = 0; subcourses != null && i < subcourses.size(); i++){
if(--inDegree[subcourses.get(i)] == 0){
queue.offer(subcourses.get(i));
}
}
}
for(int i = 0; i < numCourses; i++){
if(inDegree[i] != 0){
return false;
}
}
return true;
}
代码解释:首先我们需要根据传入和数据构建图,根据课程依赖关系的二维数组,可以统计出各个课程的入度(indegree),然后利用HashMap来构建图,注意key是先修课程,而value是一个list,代表那些依赖于key的后续课程。当这些初始化工作完成后,我们只需要用BFS遍历该图,维护一个queue,初始时队列中只有无依赖关系的可以直接上的课,每当pop出一个值时,与该课程有依赖关系的后续课程的入度减去1,当其减少至0时,代表该课程所需的先修课程已经全部完成,故将该课程也放入队列中,当队列为空时,遍历完成。此时只需要检查入度即可判断。
For Course Schedule ||
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, return the ordering of courses you should take to finish all courses.
There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.
Example
Given n = 2, prerequisites = [[1,0]]
Return [0,1]
Given n = 4, prerequisites = [1,0],[2,0],[3,1],[3,2]]
Return [0,1,2,3] or [0,2,1,3]
跟第一题相比,只是多了需要我们输出上课顺序,结题思路和第一题一模一样,利用一个一维数组记录上课顺序即可,代码如下:
public int[] findOrder(int numCourses, int[][] prerequisites) {
// write your code here
int[] inDegree = new int[numCourses];
int[] results = new int[numCourses];
int last = 0;
if(prerequisites == null || numCourses < 0){
return results;
}
if(prerequisites.length == 0){
for(int i=0; i<numCourses; i++){
results[i] = i;
}
return results;
}
HashMap<Integer, List<Integer>> graph = new HashMap<Integer, List<Integer>>();
for(int i = 0; i < prerequisites.length; i++){
inDegree[prerequisites[i][0]]++;
if(graph.containsKey(prerequisites[i][1])){
graph.get(prerequisites[i][1]).add(prerequisites[i][0]);
}else{
ArrayList<Integer> list = new ArrayList();
list.add(prerequisites[i][0]);
graph.put(prerequisites[i][1], list);
}
}
LinkedList<Integer> queue = new LinkedList();
for(int i = 0; i < numCourses; i++){
if(inDegree[i] == 0){
queue.offer(i);
}
}
last = queue.size();
for(int i=0; i<queue.size(); i++){
results[i] = queue.get(i);
}
while(!queue.isEmpty()){
int course = queue.poll();
List<Integer> subcourses = graph.get(course);
for(int i = 0; subcourses != null && i < subcourses.size(); i++){
if(--inDegree[subcourses.get(i)] == 0){
queue.offer(subcourses.get(i));
results[last] = subcourses.get(i);
last++;
}
}
}
for(int i = 0; i < numCourses; i++){
if(inDegree[i] != 0){
return new int[0];
}
}
return results;
}