問題:express
There are a total of n courses you have to take, labeled from 0
to n - 1
.ide
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]
ui
Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.spa
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:code
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]
.ip
Note:ci
Hints:get
解決:
① 與Course Schedule相同的思路,只是記錄下通過的節點的值。BFS,首先查找入度爲0 的端點,而後依次遍歷。
class Solution {//38ms
public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] res = new int[numCourses];
int p = 0;//指向結果的指針
int len = prerequisites.length;//關係的長度
if (numCourses == 0){
return res;
}
if (len == 0){//沒有關係,直接返回結果
for (int i = 0;i < numCourses;i ++){
res[i] = i;
}
return res;
}
int[] in = new int[numCourses];//記錄節點的入度。
for (int i = 0;i < len;i ++){//遍歷有向邊,初始化入度
in[prerequisites[i][0]] ++;
}
Queue<Integer> queue = new LinkedList<>();//保存入度爲0的點
for (int i = 0;i < numCourses;i ++){
if (in[i] == 0){
queue.offer(i);
}
}
int count = queue.size();//記錄入度爲0的節點數
while(! queue.isEmpty()){
int top = queue.poll();
res[p ++] = top;
for (int i = 0;i < len;i ++){//將當前節點所指向的節點的入度-1
if (prerequisites[i][1] == top){
in[prerequisites[i][0]] --;
if (in[prerequisites[i][0]] == 0){
count ++;
queue.offer(prerequisites[i][0]);
}
}
}
}
if (count == numCourses){
return res;
}else{
return new int[0];
}
}
}
② dfs的解法。
class Solution { //14ms
public static int[] findOrder(int numCourses, int[][] prerequisites) {
Map<Integer,List<Integer>> adjacent = new HashMap<>();//記錄每個節點的相鄰節點
boolean[] isvisited = new boolean[numCourses];//標記是否遍歷過
boolean[] isonstack = new boolean[numCourses];//用來標記節點入棧
List<Integer> list = new ArrayList<>();//用於存放結果
for (int[] tmp : prerequisites){//添加相鄰節點
if (! adjacent.containsKey(tmp[1])){
List<Integer> t = new ArrayList<>();
t.add(tmp[0]);
adjacent.put(tmp[1],t);
}else{
adjacent.get(tmp[1]).add(tmp[0]);
}
}
for (int i = 0;i < numCourses;i ++){//開始遍歷
if (isvisited[i]) continue;//跳過已經遍歷過的節點
if (dfs(adjacent,i,isvisited,isonstack,list)){//存在環
return new int[0];
}
}
int[] res = new int[list.size()];
for (int i = 0;i < list.size();i ++){
res[i] = list.get(i);
}
return res;
}
public static boolean dfs(Map<Integer,List<Integer>> adjacent,int i,boolean[] isvisited,
boolean[] isonstack,List<Integer> list){
isvisited[i] = true;//遍歷當前節點
isonstack[i] = true;//入棧
if (adjacent.containsKey(i) && adjacent.get(i).size() > 0){//遍歷當前節點的子節點
for (int j : adjacent.get(i)){//遞歸遍歷子節點
if (! isvisited[j] && dfs(adjacent,j,isvisited,isonstack,list)) return true;//沒有遍歷過子節點而且子節點遞歸遍歷中存在環
if (isonstack[j]) return true;//子節點已經存在於棧中,存在環
}
}
list.add(0,i);//倒序從最後一個節點開始加入結果鏈表
isonstack[i] = false;//出棧
return false;//沒有環
}
}
③ 在discuss中看到的效率最高的解法。。。
class Solution { //3ms public int[] findOrder(int numCourses, int[][] prerequisites) { int edge_len = prerequisites.length; int[] edge = new int[prerequisites.length]; int[] edge_next = new int[prerequisites.length]; int[] last = new int [numCourses]; int[] indegree = new int[numCourses]; int mark = 0; for (int i = 0;i < numCourses;i ++) last[i] = -1; for (int i = 0;i < numCourses;i ++) indegree[i] = 0; for (int i = 0;i < edge_len;i ++) { edge[mark] = prerequisites[i][0]; indegree[prerequisites[i][0]] ++; int x = prerequisites[i][1]; edge_next[mark] = last[x]; last[x] = mark; mark ++; } int[] queue = new int [numCourses]; int l = -1, r= -1; for (int i = 0;i < numCourses;i ++) { if (indegree[i] == 0) queue[++ r] = i; } while (l < r) { l ++; int now = queue[l]; int edge_now = last[now]; while (edge_now != -1) { indegree[edge[edge_now]] --; if (indegree[edge[edge_now]] == 0) queue[++ r] = edge[edge_now]; edge_now = edge_next[edge_now]; } } if (r + 1 != numCourses) return new int[0]; else return queue; } }