題目:
題解:
- 拓撲排序,與207. 課程表代碼一樣的,只是將拓撲排序的頂點保留而已,注意邊的數組給的是反向,這樣的話,我們要將res反轉就行了。
- 算法步驟:
- 1)遍歷邊的數組
prerequisites
建立圖的鄰接表
- 2)使用隊列來存放入度爲0的頂點,從而避免重複檢測入度爲0的頂點
- 3)刪除入度爲0的點,以及刪除該點爲起點的邊,並統計刪除入度爲0的頂點個數
- 4)若有向圖無環,則res.size()等於頂點數numCounses;否則有向圖有環,則res.size()會小於頂點數numCounses
拓撲排序算法思路:
- 1)在有向圖中選一個入度爲0的頂點且輸出之
- 2)從圖中刪除該頂點和所有以它爲弧尾的弧
- 3)重複上述兩步,直至全部頂點均已輸出,或者當前圖中不存在無前驅的頂點爲止。=後者表示的是該有向圖存在環。
代碼如下:
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
map<int,set<int>> adjacent;//鄰接表
vector<int> indegree(numCourses);//存放頂點入度的數組
//1、遍歷圖的邊,建立鄰接表和存放頂點入度的數組
for(auto& edge:prerequisites){
int a=edge[0],b=edge[1];
adjacent[a].insert(b);
++indegree[b];
}
//2、使用隊列來存放入度爲0的頂點,從而避免重複檢測入度爲0的頂點
queue<int> todo;
for(int i=0;i<numCourses;++i){
if(!indegree[i])todo.push(i);
}
//3、刪除入度爲0的點,以及刪除該點爲起點的邊,並統計刪除入度爲0的頂點個數
vector<int> res;
while(!todo.empty()){
auto v=todo.front();//入度爲0的頂點
todo.pop();
res.push_back(v);
auto & adjs=adjacent[v];//v的所有鄰接點,即弧頭爲v所有弧的弧尾
//對v號頂點的每個鄰接點的入度減1,若入度爲0了,則加入隊列中
for(auto adj:adjs){
--indegree[adj];
if(!indegree[adj])todo.push(adj);
}
}
//4、若有向圖無環,則count等於頂點數numCounses;否則有向圖有環,則count會小於頂點數numCounses
if(res.size()!=numCourses)return {};
//注意要將res反轉因爲圖的邊可以看成反向的,因此我們進行拓撲排序的結果需要反轉
reverse(res.begin(),res.end());
return res;
}
};