leetcode Course Schedule系列問題,拓補排序,有向無環圖

能進行拓補排序的圖必須是有向無環圖,直接用DFS判斷圖裏面是否存在環,即不能存在回邊,用兩個時鐘數組記錄每個節點的進入時鐘pre和返回時鐘post,回邊有這樣的特性,如果一條邊(u,v)是一條回邊,那麼pre(u)>pre(v)post(u)<post(v)

class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        unordered_map<int, vector<int>> adjTable;
        for (int i = 0; i < prerequisites.size(); i++) {
            adjTable[prerequisites[i].first].push_back(prerequisites[i].second);
        }
        const int arraySize = numCourses;
        bool visited[arraySize];
        int preClock[arraySize];
        int postClock[arraySize];
        int globalClock = 0;
        for (int i = 0; i < arraySize; i++) {
            visited[i] = false;
            preClock[i] = -1;
            postClock[i] = -1;
        }
        stack<int> DFSStack;
        for (int i = 0; i < numCourses; i++) {
            if (!visited[i]) {
                DFSStack.push(i);
                while (!DFSStack.empty()) {
                    int currentNode = DFSStack.top();
                    preClock[currentNode] = globalClock;
                    globalClock++;
                    visited[currentNode] = true;
                    int count = 0;
                    for (int j = 0; j < adjTable[currentNode].size(); j++) {
                        if (!visited[adjTable[currentNode][j]]) {
                            DFSStack.push(adjTable[currentNode][j]);
                            count++;
                        } else if (preClock[currentNode] > preClock[adjTable[currentNode][j]] && postClock[adjTable[currentNode][j]] == -1) {//判斷回邊的條件
                            return false;
                        }
                    }
                    if (count == 0) {
                        DFSStack.pop();
                        postClock[currentNode] = globalClock;
                        globalClock++;
                    }
                }
            }
        }
        return true;
    }
};

第二題仍然按照這個思路,不過這裏要返回排序結果,按照一種拓補排序的算法,給每個節點記錄preClock和postClock,按照postClock的遞減順序排序的話就是一種合法的拓補排序結果,而且深搜的時候,當且僅當節點被pop出棧的時候纔會計算它的postClock,所以也不需要顯式計算postClock,只需要每次pop節點的時候將這個節點插到結果向量的開頭就可以了。

算法描述:

TOPOLOGICAL-SORT(G)
1 call DFS(G) to compute finishing times post[v] for each vertex v
2 as each vertex is finished, insert it onto the front of a linked list
3 return the linked list of vertices
算法複雜度:O(V+E)
代碼:

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        unordered_map<int, vector<int>> adjTable;
        for (int i = 0; i < prerequisites.size(); i++) {
            adjTable[prerequisites[i].second].push_back(prerequisites[i].first);
        }
        int globalClock = 0;
        const int vecSize = numCourses;
        vector<int> resultVec;
        stack<int> nodeStack;
        int preClock[vecSize], postClock[vecSize];
        bool visited[vecSize];
        for (int i = 0; i < vecSize; i++) {
            preClock[i] = -1;
            postClock[i] = -1;
            visited[i] = false;
        }
        for (int startNode = 0; startNode < numCourses; startNode++) {
            if (visited[startNode]) {
                continue;
            }
            nodeStack.push(startNode);
            visited[startNode] = true;
            preClock[0] = globalClock;
            globalClock++;
            while (!nodeStack.empty()) {
                int curNode = nodeStack.top();
                bool pushFlag = false;
                for (int i = 0; i < adjTable[curNode].size(); i++) {
                    if (!visited[adjTable[curNode][i]]) {
                        nodeStack.push(adjTable[curNode][i]);
                        visited[adjTable[curNode][i]] = true;
                        preClock[adjTable[curNode][i]] = globalClock;
                        globalClock++;
                        pushFlag = true;
                        break;
                    } else if (preClock[adjTable[curNode][i]] < preClock[curNode] && postClock[adjTable[curNode][i]] == -1) {
                        return {};
                    }
                }
                if (!pushFlag) {
                    nodeStack.pop();
                    postClock[curNode] = globalClock;
                    globalClock++;
                    resultVec.insert(resultVec.begin(), curNode);
                }
            }
        }
        return resultVec;
    }
};







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章