1. 程式人生 > >LeetCode編程訓練 - 拓撲排序(Topological Sort)

LeetCode編程訓練 - 拓撲排序(Topological Sort)

hat 代碼 des vector 構建 git 算法 err cte

拓撲排序基礎

拓撲排序用於解決有向無環圖(DAG,Directed Acyclic Graph)按依賴關系排線性序列問題,直白地說解決這樣的問題:有一組數據,其中一些數據依賴其他,問能否按依賴關系排序(被依賴的排在前面),或給出排序結果。

最常用解決拓撲排序問題的方法是Kahn算法,步驟可以概括為:

1. 根據依賴關系,構建鄰接矩陣或鄰接表、入度數組
2. 取入度為0的數據(即不依賴其他數據的數據),根據鄰接矩陣/鄰接表依次減小依賴其的數據的入度
3. 判斷減小後是否有新的入度為0的數據,繼續進行第2步
4. 直到所有數據入度為0、得到拓撲排序序列,或返回失敗(存在環形依賴)

其中2、3兩個步驟取入度為0數據、減小依賴其的數據的入度,過程像樹的寬度優先搜索,用到類似BFS方法;以上過程用偽代碼表示如下:

L ← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edge
while S is non-empty do
    remove a node n from S
    add n to tail of L
    for each node m with an edge e from n to m do
        remove edge e from the graph
        if m has no other incoming edges then
            insert m into S
if graph has edges then return error (graph has at least one cycle) else return L (a topologically sorted order)

下面看具體例子 207. Course Schedule (有n個課程,課程間有依賴關系,問能否完成所有課程):

    //207. Course Schedule
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
//構建鄰接矩陣、入度數組 vector
<vector<int>> adj(numCourses); vector<int> indegree(numCourses,0); for(auto x:prerequisites){ adj[x.second].push_back(x.first); indegree[x.first]++; }
//類似BFS queue
<int> q; for(int i=0;i<numCourses;i++) if(indegree[i]==0) q.push(i); while(!q.empty()){ int cur=q.front(); q.pop(); numCourses--; for(auto next:adj[cur]) if(--indegree[next]==0) q.push(next);//新入度為0的先處理,這與正統BFS有區別 }
//判斷最後所有數據入度為0
return numCourses==0; }

以上用到鄰接矩陣(adjacency matrix)表示依賴關系,時間復雜度為O(V^2),其中V為數據個數。可視化過程:這裏

相關LeetCode題:

207. Course Schedule 題解

210. Course Schedule II 題解

444. Sequence Reconstruction 題解

269. Alien Dictionary 題解

LeetCode編程訓練 - 拓撲排序(Topological Sort)