210 课程表2
BFS
- 首先建立入度表,入度为0的节点先入队
- 当队列不为空,节点出队,标记学完课程数量的变量加1,并记录该课程
- 将课程的邻居入度减1
- 若邻居课程入度为0,加入队列
用一个变量记录学完的课程数量,一个数组记录最终结果,简洁好理解。
class Solution {
//bfs
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses == 0) {
return new int[0];
}
Queue<Integer> que = new LinkedList<>();
int[] inDegress = new int[numCourses];
int[] res = new int[numCourses];
int count = 0;
for (int[] p : prerequisites) {
inDegress[p[0]]++;
}
for (int i = 0; i < numCourses; i++) {
if (inDegress[i] == 0) {
que.add(i);
}
}
while (!que.isEmpty()) {
int integer = que.poll();
res[count++] = integer;
for (int[] p : prerequisites) {
if (p[1] == integer) {
inDegress[p[0]]--;
if (inDegress[p[0]] == 0) {
que.add(p[0]);
}
}
}
}
if (count == numCourses) {
return res;
}
return new int[0];
}
}
时间复杂度
O
(
m
+
n
)
O(m+n)
O(m+n),其中
n
n
n为课程数,
m
m
m为先修课程的要求数。这其实就是对图进行广度优先搜索的时间复杂度。
空间复杂度
O
(
n
)
O(n)
O(n)。
DFS+邻接矩阵
- 建立邻接矩阵
- DFS访问每一个课程,若存在环直接返回
status保存课程的访问状态,同一个栈保存课程的访问序列
class Solution {
//dfs+邻接矩阵,由于用的数组,每次都要遍历,效率比较低
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses == 0) {
return new int[0];
}
//建立邻接矩阵
int[][] graph = new int[numCourses][numCourses];
//记录访问状态的数组,访问过了标记-1,正在访问标记1,还未访问标记0
int[] status = new int[numCourses];
//用栈保存访问序列
Stack<Integer> stack = new Stack<Integer>();
for (int[] p : prerequisites) {
graph[p[1]][p[0]] = 1;
}
for (int i = 0; i < graph.length; i++) {
if (!dfs(graph, status, i, stack)) {
return new int[0];//只要存在环就返回
}
}
int[] res = new int[numCourses];
for (int i = 0; i < numCourses; i++) {
if (stack.isEmpty()){
break;
}
res[i] = stack.pop();
}
return res;
}
public boolean dfs(int[][] graph, int[] status, int i, Stack<Integer> stack) {
if (status[i] == 1) {
//正在访问中
//说明找到了环
return false;
}
//访问过了
if (status[i] == -1) {
return true;
}
status[i] = 1;
for (int j = 0; j < graph.length; j++) {
if (graph[i][j] == 1 && !dfs(graph, status, j, stack)) {
return false;
}
}
status[i] = -1;
stack.push(i);
return true;
}
}
时间复杂度
O
(
m
+
n
)
O(m+n)
O(m+n),其中
n
n
n为课程数,
m
m
m为先修课程的要求数,这其实就是对图进行深度优先搜索的时间复杂度。
空间复杂度
O
(
n
2
)
O(n^2)
O(n2),题目中是以列表形式给出的先修课程关系,为了对图进行深度优先搜索,需要存储成邻接矩阵的形式,空间复杂度为
O
(
n
2
)
O(n^2)
O(n2)。在深度优先搜索过程中,需要最多
O
(
n
)
O(n)
O(n)的递归栈空间进行深度优先搜索,并且还需要
O
(
n
)
O(n)
O(n)的空间存储节点状态,最终答案等。
用HashSet作为邻接矩阵
class Solution {
//hashset作为邻接表,加速查找速度
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses==0){
return new int[0];
}
HashSet<Integer>[] graph=new HashSet[numCourses];
//标记数组
int[] mark=new int[numCourses];
//结果栈
Stack<Integer> stack = new Stack<>();
for (int i=0;i<numCourses;i++){
graph[i] = new HashSet<>();
}
for (int[] p :prerequisites){
graph[p[1]].add(p[0]);
}
for (int i=0;i<numCourses;i++){
if (isCycle(graph,mark,i,stack)){
return new int[0];
}
}
int[] res=new int[numCourses];
for (int i=0;i<numCourses;i++){
res[i]=stack.pop();
}
return res;
}
private boolean isCycle(HashSet<Integer>[] graph,int[] mark,int i,Stack<Integer> stack){
if (mark[i]==1){
return true;//有环
}
if (mark[i]==-1){
return false;//没有坏
}
mark[i]=1;
for (int neibor:graph[i]){
if (isCycle(graph,mark,neibor,stack)){
return true;
}
}
stack.add(i);
mark[i]=-1;
return false;
}
}
时间复杂度
O
(
m
+
n
)
O(m+n)
O(m+n)。
空间复杂度
O
(
m
+
n
)
O(m+n)
O(m+n),邻接表。