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 ...
随机推荐
- HDU 2340 Obfuscation(dp)
题意:已知原串(长度为1~1000),它由多个单词组成,每个单词除了首尾字母,其余字母为乱序,且句子中无空格.给定n个互不相同的单词(1 <= n <= 10000),问是否能用这n个单词 ...
- 如何找到Linux下常用命令的源码
Linux系统,常用命令的来源很多,有些命令是shell自带的,比如cd,通过执行help命令,可以查看当前系统所有的内置命令. 用type <cmd_name>来查看一个命令是否为内置命 ...
- WSAEventSelect模型详解
WSAEventSelect 是 WinSock 提供的一种异步事件通知I/O模型,与 WSAAsyncSelect模型有些类似. 该模型同样是接收 FD_XXX 之类的网络事件,但是是通 ...
- 【winform】如何在DateTimePicker中显示时分秒
1. 首先属性里面的Format属性value设置为Custom(默认为Long) 2. 对应的Custom属性value设置为yyyy-MM-dd HH:mm:ss
- 【Qt】Qt Creator键盘快捷键速查
附录 Qt Creator键盘快捷键速查 一般操作的键盘快捷键 操作 快捷键 操作 快捷键 打开文件或项目 Ctrl+O 新建文件或项目 Ctrl+N 在外部编辑器中打开 Alt+V,Alt+I 选择 ...
- GDI+ 绘图闪烁解决方法
闲着没事,准备做一个类似于TeeChart的自定义控件,结果第一步的绘图就把我给难倒了,虽然早就知道GDI绘图的闪烁问题很坑,但是却没有想到如此之坑,折腾了两天,才找到解决方法. 首先在窗体加载的时候 ...
- 解决Ajax跨域问题:Origin xx is not allowed by Access-Control-Allow-Origin.
一:使用jsonp格式, 如jquery中ajax请求参数 dataType:'JSONP'. <html> <head> <title>title</t ...
- linux系统文件属性及企业精典故障案例
linux系统文件属性: [root@nginx_back ~]# stat keepalived-1.2.7.tar.gz 查看文件属性 File: "keepalived-1.2.7.t ...
- linux 输入子系统(1)----系统概述
输入设备的工作中,只是中断.读键值/坐标值是设备相关的,而输入事件的缓冲区管理以及字符设备驱动的file_operations接口则对输入设备是通用的,基于此,内核设计了input输入子系统,由核心层 ...
- Java 类和对象
主要参考文献:王映龙<Java程序设计> 一:类的语法 [修饰符]class<类名>[extends父类名][implements接口列表]{ //类体} 1:修饰符 可选值为 ...