210. Course Schedule II
题目:
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.
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 the correct course order is [0,1]
4, [[1,0],[2,0],[3,1],[3,2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
- This problem is equivalent to finding the topological order in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
- Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
- Topological sort could also be done via BFS.
链接: http://leetcode.com/problems/course-schedule-ii/
题解:
跟Course Schedule一样,这次是求出拓扑排序后的顺序。我们依然是用Kahn's Algorithm和Tarjan's Algorithm。
Kahn's Algorithm: 需要注意输出的先后顺序,edge [0,1]表示假如要take 0,必须先take 1,那么edge[0]也就是0其实inDegree = 1,而edge[1]也就是1的indegree = 0。这个edge等价于"1 -> 0"。
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) { // Kahn's Algorithms
if(numCourses <= 0)
return new int[]{};
int[] res = new int[numCourses];
for(int i = 0; i < numCourses; i++)
res[i] = i;
if(prerequisites == null || prerequisites.length == 0)
return res;
int[] inDegree = new int[numCourses];
for(int[] edge : prerequisites)
inDegree[edge[0]]++;
Queue<Integer> queue = new LinkedList<>();
for(int i = 0; i < numCourses; i++) // calculate inDegree
if(inDegree[i] == 0)
queue.offer(i);
int index = 0;
while(!queue.isEmpty()) {
int source = queue.poll();
res[index++] = source; // reverse post order
for(int[] edge : prerequisites) {
if(edge[1] == source) {
inDegree[edge[0]]--;
if(inDegree[edge[0]] == 0)
queue.offer(edge[0]);
}
}
}
if(index == numCourses) { //looped through all vertex
return res;
} else
return new int[]{}; // has cycle, not DAG
}
}
Tarjan's Algorithm: 也是使用跟Course Schedule I的方法,注意要有一个stack保存reverse post顺序。虽然能ac,但是速度很慢, 二刷要注意复杂度的问题,以及图的表示,从list of edges到Ajacency Matrix和Ajacency List的互相转换。以及Sparse Matrix如何优化等等。
Time Complexity - O(VE),Space Complexity - O(V)。
public class Solution {
private boolean[] marked; // mark visited vertex
private boolean[] onStack; // mark temp visited vertex for dfs
private Stack<Integer> reversePost; // store topological ordering vertex
private boolean result = true;
public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] res = new int[numCourses];
for(int i = 0; i < numCourses; i++)
res[i] = i;
if(prerequisites == null || prerequisites.length == 0)
return res;
this.marked = new boolean[numCourses];
this.onStack = new boolean[numCourses];
this.reversePost = new Stack<>();
for(int v = 0; v < numCourses; v++) {
if(!this.result) // if found cycle
return new int[]{};
if(!marked[v])
dfs(v, prerequisites);
}
int index = 0;
while(!reversePost.isEmpty()) {
res[index++] = reversePost.pop();
}
return res;
}
private void dfs(int v, int[][] prerequisites) {
onStack[v] = true; // temporarily mark this vertex = true on this dfs route
marked[v] = true; // permanently mark this vertex visited
for(int[] edge : prerequisites) {
if(edge[1] == v) {
if(!marked[edge[0]])
dfs(edge[0], prerequisites);
else {
if(onStack[edge[0]])
this.result = false;
}
}
}
onStack[v] = false; // back-tracking
reversePost.push(v); // push vertex to reversePost stack
}
}
二刷:
和 207题一样, 以后要注意转为 Adjacency Lists表示方法进行计算。
Java:
Kahn's Method
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses <= 0 || prerequisites == null) return new int[] {};
int[] inDegree = new int[numCourses];
for (int[] prerequisite : prerequisites) inDegree[prerequisite[0]]++;
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (inDegree[i] == 0) q.offer(i);
}
int[] res = new int[numCourses];
int index = 0;
while (!q.isEmpty()) {
int num = q.poll();
res[index++] = num;
for (int[] prerequisite : prerequisites) {
if (prerequisite[1] == num) {
inDegree[prerequisite[0]]--;
if (inDegree[prerequisite[0]] == 0) {
q.offer(prerequisite[0]);
}
}
}
}
return index == numCourses ? res : new int[] {};
}
}
Tarjan's method:
速度非常慢,下次再优化
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses <= 0 || prerequisites == null) return new int[] {};
boolean[] visited = new boolean[numCourses];
boolean[] onVisiting = new boolean[numCourses];
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < numCourses; i++) {
if (!dfs(i, prerequisites, visited, onVisiting, stack)) return new int[] {};
}
int[] res = new int[numCourses];
for (int i = numCourses - 1; i >= 0; i--) res[i] = stack.pop();
return res;
}
private boolean dfs(int i, int[][] prerequisites, boolean[] visited, boolean[] onVisiting, Stack<Integer> stack) {
if (visited[i]) return true;
visited[i] = true;
onVisiting[i] = true;
for (int[] prerequisite : prerequisites) {
if (prerequisite[0] == i) {
if (onVisiting[prerequisite[1]]) return false;
if (!dfs(prerequisite[1], prerequisites, visited, onVisiting, stack)) return false;
}
}
onVisiting[i] = false;
stack.push(i);
return true;
}
}
优化后:
Kahn's Method - BFS using Graph as Adjacency Lists
Time Complexity - O(V + E),Space Complexity - O(V)。
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses <= 0 || prerequisites == null) return new int[] {};
int[] inDegree = new int[numCourses];
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < numCourses; i++) graph.add(new ArrayList<Integer>());
for (int i = 0; i < prerequisites.length; i++) {
inDegree[prerequisites[i][0]]++;
graph.get(prerequisites[i][1]).add(prerequisites[i][0]);
}
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (inDegree[i] == 0) q.offer(i);
}
int[] res = new int[numCourses];
int index = 0;
while (!q.isEmpty()) {
int num = q.poll();
res[index++] = num;
for (int i : graph.get(num)) {
inDegree[i]--;
if (inDegree[i] == 0) {
q.offer(i);
}
}
}
return index == numCourses ? res : new int[] {};
}
}
Tarjan's Method - BFS using Graph as Adjacency Lists
Time Complexity - O(V + E),Space Complexity - O(V)。
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses <= 0 || prerequisites == null) return new int[] {};
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < numCourses; i++) graph.add(new ArrayList<Integer>());
for (int i = 0; i < prerequisites.length; i++) graph.get(prerequisites[i][1]).add(prerequisites[i][0]);
boolean[] visited = new boolean[numCourses];
boolean[] onVisiting = new boolean[numCourses];
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < numCourses; i++) {
if (!dfs(i, graph, visited, onVisiting, stack)) return new int[] {};
}
int[] res = new int[numCourses];
for (int i = 0; i < numCourses; i++) res[i] = stack.pop();
return res;
}
private boolean dfs(int num, List<List<Integer>> graph, boolean[] visited, boolean[] onVisiting, Stack<Integer> stack) {
if (visited[num]) return true;
visited[num] = true;
onVisiting[num] = true;
for (int i : graph.get(num)) {
if (onVisiting[i]) return false;
if (!dfs(i, graph, visited, onVisiting, stack)) return false;
}
onVisiting[num] = false;
stack.push(num);
return true;
}
}
三刷:
Java:
BFS:
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses < 0 || prerequisites == null) return new int[] {};
List<List<Integer>> adjListsGraph = new ArrayList<>();
for (int i = 0; i < numCourses; i++) adjListsGraph.add(new ArrayList<>());
int[] inDegrees = new int[numCourses];
for (int[] prerequisite : prerequisites) {
adjListsGraph.get(prerequisite[1]).add(prerequisite[0]);
inDegrees[prerequisite[0]]++;
}
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (inDegrees[i] == 0) q.offer(i);
}
int[] res = new int[numCourses];
int idx = 0;
while (!q.isEmpty()) {
int course = q.poll();
res[idx++] = course;
for (int dependent : adjListsGraph.get(course)) {
inDegrees[dependent]--;
if (inDegrees[dependent] == 0) q.offer(dependent);
}
}
return (idx == numCourses) ? res : new int[] {};
}
}
DFS:
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses < 0 || prerequisites == null) return new int[] {};
List<List<Integer>> adjListsGraph = new ArrayList<>();
for (int i = 0; i < numCourses; i++) adjListsGraph.add(new ArrayList<>());
for (int[] prerequisite : prerequisites) adjListsGraph.get(prerequisite[1]).add(prerequisite[0]);
boolean[] visited = new boolean[numCourses];
boolean[] onVisitingPath = new boolean[numCourses];
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < numCourses; i++) {
if (!visited[i] && !canFindOrder(i, adjListsGraph, visited, onVisitingPath, stack)) return new int[] {};
}
int[] res = new int[numCourses];
for (int i = 0; i < numCourses; i++) res[i] = stack.pop();
return res;
}
private boolean canFindOrder(int course, List<List<Integer>> adjListsGraph, boolean[] visited, boolean[] onVisitingPath, Stack<Integer> stack) {
if (visited[course]) return true;
onVisitingPath[course] = true;
for (int dependent : adjListsGraph.get(course)) {
if (onVisitingPath[dependent] || !canFindOrder(dependent, adjListsGraph, visited, onVisitingPath, stack)) {
return false;
}
}
onVisitingPath[course] = false;
visited[course] = true;
stack.push(course);
return true;
}
}
Reference:
http://algs4.cs.princeton.edu/42digraph/
210. Course Schedule II的更多相关文章
- 【LeetCode】210. Course Schedule II
Course Schedule II There are a total of n courses you have to take, labeled from 0 to n - 1. Some co ...
- 【刷题-LeetCode】210. Course Schedule II
Course Schedule II There are a total of n courses you have to take, labeled from 0 to n-1. Some cour ...
- [LeetCode] 210. Course Schedule II 课程清单之二
There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may have prereq ...
- Java for LeetCode 210 Course Schedule II
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prer ...
- Leetcode 210 Course Schedule II
here are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prere ...
- LeetCode 210. Course Schedule II(拓扑排序-求有向图中是否存在环)
和LeetCode 207. Course Schedule(拓扑排序-求有向图中是否存在环)类似. 注意到.在for (auto p: prerequistites)中特判了输入中可能出现的平行边或 ...
- [LeetCode] 210. Course Schedule II 课程安排II
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prer ...
- 【LeetCode】210. Course Schedule II 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 拓扑排序,BFS 拓扑排序,DFS 参考资料 日期 ...
- (medium)LeetCode 210.Course Schedule II
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prer ...
随机推荐
- vs2005_the breakpoint will not currently be hit. The source code is different from the original verison.
公司开发只能用英文版的VS2005 (雅蠛蝶) Tool-->Options-->Debugging->General: 把Require source files to exact ...
- C++运用SDK截屏
引言 最近有一个需要截取当前屏幕,并保存成BMP文件的需求.整个需求,拆分成三步:1.截取屏幕,获得位图数据.2.配合bmp文件结构信息,将数据整合.3.对整合后的数据做操作,如保存在本地.通过网络传 ...
- XPOSED-LUA
转载说明 本篇文章可能已经更新,最新文章请转:http://www.sollyu.com/xposed-lua/ 说明 Xposed Lua Module 是一个Xposed的模块,他有下面的优点 本 ...
- jQuery—一些常见方法(1)【filter(),not(),has(),next(),prev(),find(),eq(),index(),attr(),】
1.filter()和not()方法 filter()和not()是一对反方法,filter()是过滤. filter()方法是针对元素自身.(跟has()方法有区别) <script type ...
- gen-cpp/.deps/ChildService.Plo: No such file or directory
最近在编译 Thrift 的时候出现这种情况,我按照官方教程的要求,所有版本都是最新,但是还出现这种问题. ]: Entering directory `/home/yantze/dl/thrift/ ...
- iOS Mac系统下Ruby环境安装
由EasyIOS引出的一系列问题:转载的上一篇CocoaPods安装和使用教程中说明了,为什么要使用cocoapods ,但是要安装cocoapods需要Ruby环境,安装Ruby环境首先需要安装Xc ...
- Sublime Text 前端插件推荐
html/CSS快速编辑 --- Emment HTML CSS JS 美化插件 --- HTML/CSS/JS Prettyfy MarkDown 预览 --- MarkDown Preview J ...
- CentOS平台下为Python添加MongoDB支持PyMongo
下载PyMongo [root@leezhen ~]# wget https://pypi.python.org/packages/source/p/pymongo/pymongo-2.6.3.tar ...
- linux系统文件属性及企业精典故障案例
linux系统文件属性: [root@nginx_back ~]# stat keepalived-1.2.7.tar.gz 查看文件属性 File: "keepalived-1.2.7.t ...
- ubuntu14.04 中文输入法无法使用
说下我的解决方法吧,我是忘了在All Settings -> Text Entry 的 Input sources to use中添加Chinese(Pinyin)了,添加后就好了. from: ...