LeetCode 210-Course Schedule II

There are a total of n courses you have to take, labeled from 0 to n - 1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

For example:

2, [[1,0]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1]

4, [[1,0],[2,0],[3,1],[3,2]]

There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].

Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.

題意

共有n節(jié)課程,課程編號從0至n-1。一些課程可能有先修要求,比如修0號課程前需要先修1號課程,表示為[0,1]蔼两。題目給出課程數(shù)和先后修課程對,要求返回完成所有課程的順序∷憷可能有很多正確的上課順序,你只需返回其中一種泳姐。如果不可能完成效拭,則返回空數(shù)組。

比如:

2, [[1,0]]

共有2節(jié)課程。選修1號課程前需要先修0號課程缎患,故上課順序?yàn)?code>[0,1]慕的。

4, [[1,0],[2,0],[3,1],[3,2]]

共有4節(jié)課程。正確的上課順序?yàn)?code>[0,2,1,3]挤渔。

提示:

輸入的prerequisites是由邊表示的圖肮街,而非鄰接矩陣。

分析

此題是Leetcode207-Course Schedule的進(jìn)階版判导,前者只需得出能否完成所有課程即可嫉父,本題還需要給出上課順序。實(shí)際上這是一個求拓?fù)渑判虻念}(至于是拓?fù)淙蜻€是拓?fù)淦蜓廴校遣灰欢ǖ模┤葡健?梢杂?種求解方法擂红。

  • 第一種:采用bfs仪际。前處理時得到每個節(jié)點(diǎn)的入度。每次將入度為0的節(jié)點(diǎn)入隊(duì)昵骤。出隊(duì)時將出隊(duì)節(jié)點(diǎn)的鄰接節(jié)點(diǎn)的入度減1树碱,并將出隊(duì)節(jié)點(diǎn)編號計(jì)入answer數(shù)組中。循環(huán)該過程直到隊(duì)列為空变秦。如仍有節(jié)點(diǎn)未被訪問成榜,則說明課程關(guān)系圖中出現(xiàn)了環(huán),不可能完成所有課程伴栓。否則伦连,answer中的編號順序就是上課順序。

  • 第二種:采用dfs钳垮。需要一個onStack數(shù)組紀(jì)錄dfs的路徑上的節(jié)點(diǎn)惑淳,用于判斷環(huán)的存在。而isVisited數(shù)組責(zé)紀(jì)錄dfs中訪問過的節(jié)點(diǎn)饺窿。而其reversePostOrder就是上課順序歧焦。具體可以google搜索reversePostOrder。這種方法比較難理解肚医,但很有意思绢馍。最終給出的AC代碼也是第二種方法。

注意

  • 值得注意的是肠套,特殊情況輸入numCourses = 1舰涌,prereqisities為空數(shù)組時,答案為[0]你稚,只有1個節(jié)點(diǎn)瓷耙,并沒有邊的存在朱躺。

  • 第二種方法中onStack在每次結(jié)束本次遞歸時,需要變?yōu)閒alse搁痛,表示這條路徑上后面的節(jié)點(diǎn)在后面的判斷環(huán)中长搀,不會被認(rèn)為是同一路徑上的節(jié)點(diǎn)。(感覺好繞)

AC代碼

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<int> answer;
        if (numCourses == 1) {
            answer.push_back(0); return answer;
        }
        vector<vector<int>> map(numCourses, vector<int>());
        stack<int> reversePostOrder;
        for (int i = 0; i < prerequisites.size(); ++i) {
            map[prerequisites[i].second].push_back(prerequisites[i].first);
        }
        vector<bool> isVisited(numCourses, false);
        for (int i = 0; i < numCourses; ++i) {
            if (!isVisited[i]) {
                vector<bool> onStack(numCourses, false);
                if (hasCycle(map, i, isVisited, onStack, reversePostOrder))
                    return answer;
            }
        }
        while (!reversePostOrder.empty()) {
            int index = reversePostOrder.top(); reversePostOrder.pop();
            answer.push_back(index);
        }
        return answer;
    }
    bool hasCycle(vector<vector<int>> &map, int i, vector<bool> &isVisited, vector<bool> &onStack, stack<int> &reversePostOrder) {
        isVisited[i] = true;
        onStack[i] = true;
        for (int k : map[i]) {
            if (onStack[k])
                return true;
            else if (!isVisited[k])
                if (hasCycle(map, k, isVisited, onStack, reversePostOrder))
                    return true;
        }
        onStack[i] = false;
        reversePostOrder.push(i);
        return false;
    }
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸡典,一起剝皮案震驚了整個濱河市源请,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌彻况,老刑警劉巖谁尸,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疗垛,居然都是意外死亡症汹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門贷腕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咬展,你說我怎么就攤上這事泽裳。” “怎么了破婆?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵涮总,是天一觀的道長。 經(jīng)常有香客問我祷舀,道長瀑梗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任裳扯,我火速辦了婚禮抛丽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘饰豺。我一直安慰自己亿鲜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布冤吨。 她就那樣靜靜地躺著蒿柳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪漩蟆。 梳的紋絲不亂的頭發(fā)上垒探,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機(jī)與錄音怠李,去河邊找鬼圾叼。 笑死仔引,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的褐奥。 我是一名探鬼主播咖耘,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼撬码!你這毒婦竟也來了儿倒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤呜笑,失蹤者是張志新(化名)和其女友劉穎夫否,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叫胁,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凰慈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了驼鹅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片微谓。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖输钩,靈堂內(nèi)的尸體忽然破棺而出豺型,到底是詐尸還是另有隱情,我是刑警寧澤买乃,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布姻氨,位于F島的核電站,受9級特大地震影響剪验,放射性物質(zhì)發(fā)生泄漏肴焊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一功戚、第九天 我趴在偏房一處隱蔽的房頂上張望娶眷。 院中可真熱鬧,春花似錦疫铜、人聲如沸茂浮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽席揽。三九已至,卻和暖如春谓厘,著一層夾襖步出監(jiān)牢的瞬間幌羞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工竟稳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留属桦,地道東北人熊痴。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像聂宾,于是被迫代替她去往敵國和親果善。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容