一、題目
注意;輸入條件是鄰接表,而不是鄰接矩陣。假設沒有重複邊
題目分析:
題目是說,課程之間有依賴關係,必須完成一門之前,先完成它的依賴課程。
所以,如果有環的話,就不可能完成所有的課程。因此題目就是判斷,圖中是否有環。
(1)可以使用深度優先遍歷(DFS)
思路是,正在進行該節點的遞歸深度搜索,如果回到了該節點,就說明有環
(2)可以使用寬度優先遍歷(BFS)
記錄所有節點的入度
根據入度的計算,搜索完一個節點,把它從途中拿掉,因此後續節點的入度都減一,即將入度爲0的節點記錄到list中,如果所有節點入度都爲0,則無環
二、
(1)DFS
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
//建立鄰接表,因爲題目中說不讓用鄰接矩陣
ArrayList[] list=new ArrayList[numCourses];//所有節點
for(int i=0;i<numCourses;i++){
list[i]=new ArrayList<Integer>();//每個節點的後續節點
}
for(int i=0;i<prerequisites.length;i++){
//因爲數組後面一項依賴前面一項
list[prerequisites[i][1]].add(prerequisites[i][0]);
}
boolean[] visit=new boolean[numCourses];
for(int i=0;i<numCourses;i++){
if(!dfs(list,visit,i)){//遍歷i節點的後續節點 dfs爲false表示憂患,進入if循環,返回false
return false;
}
}
return true;
}
//深度遍歷,如果節點訪問過,返回false 表示有環,不能訪問
//如果節點未訪問過,將visit設置爲true
public boolean dfs(ArrayList[] list, boolean[] visit, int num){
if(visit[num]){
return false;
}
else{
visit[num]=true;
}
for(int i=0;i<list[num].size();i++){//後續節點的dfs
if(!dfs(list,visit,(int)list[num].get(i))){//後續節點i已經訪問過
return false;
}
list[num].remove(i);
}
visit[num]=false;
return true;
}
}
(2)BFS
public class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<Integer>[] adj = new List[numCourses];
for(int i = 0; i < numCourses; i++)
adj[i] = new ArrayList<Integer>();
int[] indegree = new int[numCourses];
Queue<Integer> readyCourses = new LinkedList();
int finishCount = 0;
for (int i = 0; i < prerequisites.length; i++)
{
int curCourse = prerequisites[i][0];
int preCourse = prerequisites[i][1];
adj[preCourse].add(curCourse);
indegree[curCourse]++;
}
for (int i = 0; i < numCourses; i++)
{
if (indegree[i] == 0)
readyCourses.offer(i);
}
while (!readyCourses.isEmpty())
{
int course = readyCourses.poll(); // finish
finishCount++;
for (int nextCourse : adj[course])
{
indegree[nextCourse]--;
if (indegree[nextCourse] == 0)
readyCourses.offer(nextCourse); // ready
}
}
return finishCount == numCourses;
}
}