拓撲排序就這麼回事

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#ffffff","name":"user"}}],"text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大家好,這裏是《齊姐聊算法》系列之拓撲排序問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Topological sort 又稱 Topological order,這個名字有點迷惑性,因爲拓撲排序並不是一個純粹的排序算法,它只是針對"},{"type":"text","marks":[{"type":"strong"}],"text":"某一類圖"},{"type":"text","text":",找到一個可以執行的線性順序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個算法聽起來高大上,如今的面試也很愛考,比如當時我在面我司時有整整一輪是基於拓撲排序的設計。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但它其實是一個很好理解的算法,跟着我的思路,讓你再也不會忘記她。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#ffffff","name":"user"}}],"text":"有向無環圖"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"剛剛我們提到,拓撲排序只是針對特定的一類圖,那麼是針對哪類圖的呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"答:Directed acyclic graph (DAG),有向無環圖。即:"}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"這個圖的邊必須是有方向的;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"圖內無環。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼什麼是方向呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如微信好友就是有向的,你加了他好友他可能把你刪了你卻不知道。。。那這個朋友關係就是單向的。。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"什麼是環?環是和方向有關的,從一個點出發能回到自己,這是環。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以下圖左邊不是環,右邊是。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2d/2d1d5edafe4e2b04041657d5014464bd.jpeg","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼如果一個圖裏有環,比如右圖,想執行 1 就要先執行 3,想執行 3 就要先執行 2,想執行 2 就要先執行 1,這成了個死循環,無法找到正確的打開方式,所以找不到它的一個拓撲序。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"總結:"}]},{"type":"blockquote","content":[{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"如果這個圖不是 DAG,那麼它是沒有拓撲序的;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"如果是 DAG,那麼它至少有一個拓撲序;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"反之,如果它存在一個拓撲序,那麼這個圖必定是 DGA."}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以這是一個"},{"type":"text","marks":[{"type":"strong"}],"text":"充分必要條件"},{"type":"text","text":"。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/22/228b7c1d9159580ea1898a27ed208cab.jpeg","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#ffffff","name":"user"}}],"text":"拓撲排序"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼這麼一個圖的"},{"type":"codeinline","content":[{"type":"text","text":"「拓撲序」"}]},{"type":"text","text":"是什麼意思呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們借用"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#ff3502","name":"user"}},{"type":"strong"}],"text":"百度百科"},{"type":"text","marks":[{"type":"strong"}],"text":"[1]"},{"type":"text","text":"的這個課程表來說明。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"課程代號課程名稱先修課程"},{"type":"text","text":"C1高等數學無"},{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#F8F8F8","name":"user"}}],"text":"C2程序設計基礎無"},{"type":"text","text":"C3離散數學C1, C2"},{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#F8F8F8","name":"user"}}],"text":"C4數據結構C3, C5"},{"type":"text","text":"C5算法語言C2"},{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#F8F8F8","name":"user"}}],"text":"C6編譯技術C4, C5"},{"type":"text","text":"C7操作系統C4, C9"},{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#F8F8F8","name":"user"}}],"text":"C8普通物理C1"},{"type":"text","text":"C9計算機原理C8"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏有 9 門課程,有些課程是有先修課程的要求的,就是你要先學了「最右側這一欄要求的這個課」才能再去選「高階」的課程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼這個例子中拓撲排序的意思就是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"就是求解一種可行的順序,能夠讓我把所有課都學了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那怎麼做呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先我們可以用"},{"type":"codeinline","content":[{"type":"text","text":"圖"}]},{"type":"text","text":"來描述它,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圖的兩個要素是"},{"type":"codeinline","content":[{"type":"text","text":"頂點和邊"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼在這裏:"}]},{"type":"blockquote","content":[{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"頂點:每門課"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"邊:起點的課程是終點的課程的先修課"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"畫出來長這個樣:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/27/276a682688b04591737e04647ad9307d.jpeg","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種圖叫 "},{"type":"text","marks":[{"type":"strong"}],"text":"AOV"},{"type":"text","text":" (Activity On Vertex) 網絡,在這種圖裏:"}]},{"type":"blockquote","content":[{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"頂點:表示活動;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"邊:表示活動間的先後關係"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"所以一個 AOV 網應該是一個 DAG,即有向無環圖,否則某些活動會無法進行。那麼所有活動可以排成一個可行線性序列,這個序列就是"},{"type":"codeinline","content":[{"type":"text","text":"拓撲序列"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼這個序列的"},{"type":"codeinline","content":[{"type":"text","text":"實際意義"}]},{"type":"text","text":"是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"按照這個順序,在每個項目開始時,能夠保證它的前驅活動都已完成,從而使整個工程順利進行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回到我們這個例子中:"}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"我們一眼可以看出來要先學 C1, C2,因爲這兩門課沒有任何要求嘛,大一的時候就學唄;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"大二就可以學第二行的 C3, C5, C8 了,因爲這三門課的先修課程就是 C1, C2,我們都學完了;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"大三可以學第三行的 C4, C9;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"最後一年選剩下的 C6, C7。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣,我們就把所有課程學完了,也就得到了這個圖的"},{"type":"text","marks":[{"type":"strong"}],"text":"一個"},{"type":"codeinline","content":[{"type":"text","text":"拓撲排序"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意,有時候拓撲序並不是唯一的,比如在這個例子中,先學 C1 再學 C2,和先 C2 後 C1 都行,都是這個圖的正確的拓撲序,但這是兩個順序了。"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}}],"text":"所以面試的時候要問下面試官,是要求解任意解,還是列出所有解。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們總結一下,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"在這個圖裏的"},{"type":"codeinline","content":[{"type":"text","text":"邊"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"表示的是一種"},{"type":"codeinline","content":[{"type":"text","text":"依賴關係"}],"marks":[{"type":"strong"}]},{"type":"text","text":",如果要修下一門課,就要先把前一門課修了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這和打遊戲裏一樣一樣的嘛,要拿到一個道具,就要先做 A 任務,再完成 B 任務,最終終於能到達目的地了。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#ffffff","name":"user"}}],"text":"算法詳解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面的圖裏,大家很容易就看出來了它的拓撲序,但當工程越來越龐大時,依賴關係也會變得錯綜複雜,那就需要用一種系統性的方式方法來求解了。"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}}],"text":"那麼我們回想一下剛剛自己找拓撲序的過程,爲什麼我們先看上了 C1, C2?"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲它們沒有依賴別人啊,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也就是它的"},{"type":"codeinline","content":[{"type":"text","text":"入度爲 0"}]},{"type":"text","text":"."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"入度"},{"type":"text","text":":頂點的入度是指「"},{"type":"text","marks":[{"type":"strong"}],"text":"指向該頂點的邊"},{"type":"text","text":"」的數量;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"出度"},{"type":"text","text":":頂點的出度是指該頂點指向其他點的邊的數量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以我們先執行入度爲 0 的那些點,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那也就是要記錄每個頂點的入度。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲"},{"type":"text","marks":[{"type":"strong"}],"text":"只有當它的 "},{"type":"codeinline","content":[{"type":"text","text":"入度 = 0"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":" 的時候,我們才能執行它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在剛纔的例子裏,最開始 C1, C2 的入度就是 0,所以我們可以先執行這兩個。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那在這個算法裏第一步就是得到每個頂點的入度。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Step0: 預處理得到每個點的入度"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以用一個 HashMap 來存放這個信息,或者用一個"},{"type":"codeinline","content":[{"type":"text","text":"數組"}]},{"type":"text","text":"會更精巧。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在文中爲了方便展示,我就用表格了:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C1C2C3C4C5C6C7C8C9"},{"type":"text","text":"入度002212211"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(不好意思沒有找到貴平臺的表格功能,還請大家移步我的 Github 查看"},{"type":"link","attrs":{"href":"https://github.com/xiaoqi6666/NYCSDE","title":null},"content":[{"type":"text","text":"https://github.com/xiaoqi6666/NYCSDE"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":",在我的倉庫裏搜索「拓撲」即可看到)"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Step1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"拿到了這個之後,就可以執行入度爲 0 的這些點了,也就是 C1, C2."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那我們把可以被執行的這些點,放入一個"},{"type":"codeinline","content":[{"type":"text","text":"待執行的容器"}]},{"type":"text","text":"裏,這樣之後我們一個個的從這個容器裏取頂點就好了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至於這個"},{"type":"codeinline","content":[{"type":"text","text":"容器"}]},{"type":"text","text":"究竟選哪種"},{"type":"codeinline","content":[{"type":"text","text":"數據結構"}]},{"type":"text","text":",這取決於我們需要做哪些"},{"type":"codeinline","content":[{"type":"text","text":"操作"}]},{"type":"text","text":",再看哪種數據結構可以爲之服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼首先可以把"},{"type":"codeinline","content":[{"type":"text","text":"[C1, C2]"}]},{"type":"text","text":"放入"},{"type":"codeinline","content":[{"type":"text","text":"容器"}]},{"type":"text","text":"中,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後想想我們需要哪些操作吧!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們最常做的操作無非就是"},{"type":"codeinline","content":[{"type":"text","text":"把點放進來"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"把點拿出去"}]},{"type":"text","text":"執行了,也就是需要一個 "},{"type":"codeinline","content":[{"type":"text","text":"offer"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"poll"}]},{"type":"text","text":" 操作比較高效的數據結構,那麼 "},{"type":"codeinline","content":[{"type":"text","text":"queue"}]},{"type":"text","text":" 就夠用了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(其他的也行,放進來這個容器裏的頂點的地位都是一樣的,都是可以執行的,和進來的順序無關,但何必非得給自己找麻煩呢?一個常規順序的簡簡單單的 queue 就夠用了。)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後就需要把某些點拿出去執行了。"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}}],"text":"【劃重點】當我們把 C1 拿出來執行,那這意味這什麼?"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"答:意味着「以 C1 爲頂點」的「指向其他點」的「邊」都消失了,也就是 C1 的出度變成了 0."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如下圖,也就是這兩條邊可以消失了。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/16/168816a1f8693f491cc74a3b638dbca8.gif","alt":"step1","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"step1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼此時我們就可以更新 "},{"type":"codeinline","content":[{"type":"text","text":"C1 所指向的那些點"}]},{"type":"text","text":"也就是 "},{"type":"codeinline","content":[{"type":"text","text":"C3 和 C8"}]},{"type":"text","text":" 的 "},{"type":"codeinline","content":[{"type":"text","text":"入度"}]},{"type":"text","text":" 了,更新後的數組如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C3C4C5C6C7C8C9"},{"type":"text","text":"入度12122"},{"type":"text","marks":[{"type":"strong"}],"text":"0"},{"type":"text","text":"1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"那我們這裏看到很關鍵的一步,C8 的入度變成了 0!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"也就意味着 C8 此時沒有了任何依賴,可以放到我們的 queue 裏等待執行了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此時我們的 "},{"type":"codeinline","content":[{"type":"text","text":"queue"}]},{"type":"text","text":" 裏就是:"},{"type":"codeinline","content":[{"type":"text","text":"[C2, C8]"}]},{"type":"text","text":"."}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Step2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下一個我們再執行 C2,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/06/06c11e91a7102cdb77b58f5c93c99678.gif","alt":"Step2","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Step2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼 "},{"type":"codeinline","content":[{"type":"text","text":"C2 所指向的"}]},{"type":"text","text":" "},{"type":"codeinline","content":[{"type":"text","text":"C3, C5"}]},{"type":"text","text":" 的 "},{"type":"codeinline","content":[{"type":"text","text":"入度-1"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更新表格:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C3C4C5C6C7C9"},{"type":"text","text":"入度"},{"type":"text","marks":[{"type":"strong"}],"text":"0"},{"type":"text","text":"2"},{"type":"text","marks":[{"type":"strong"}],"text":"0"},{"type":"text","text":"221"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也就是 C3 和 C5 都沒有了任何束縛,可以放進 queue 裏執行了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"queue"}]},{"type":"text","text":" 此時變成:"},{"type":"codeinline","content":[{"type":"text","text":"[C8, C3, C5]"}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Step3"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼下一步我們執行 C8,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8c/8cc5936a7d303fb84d41e40944887763.gif","alt":"Step3","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Step3"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相應的 C8 所指的 C9 的入度-1."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更新表格:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C4C6C7C9"},{"type":"text","text":"入度222"},{"type":"text","marks":[{"type":"strong"}],"text":"0"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼 C9 沒有了任何要求,可以放進 queue 裏執行了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"queue"}]},{"type":"text","text":" 此時變成:"},{"type":"codeinline","content":[{"type":"text","text":"[C3, C5, C9]"}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Step4"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來執行 C3,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/06/06c11e91a7102cdb77b58f5c93c99678.gif","alt":"Step4","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Step4"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相應的 C3 所指的 C4 的入度-1."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更新表格:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C4C6C7"},{"type":"text","text":"入度"},{"type":"text","marks":[{"type":"strong"}],"text":"1"},{"type":"text","text":"22"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"但是 C4 的入度並沒有變成 0,所以這一步沒有任何點可以加入 queue."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"queue"}]},{"type":"text","text":" 此時變成 "},{"type":"codeinline","content":[{"type":"text","text":"[C5, C9]"}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Step5"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再執行 C5,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/13/13e1747adf52db359b82466c6c1bb681.gif","alt":"Step5","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Step5"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼 C5 所指的 C4 和 C6 的入度- 1."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更新表格:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C4C6C7"},{"type":"text","text":"入度"},{"type":"text","marks":[{"type":"strong"}],"text":"01"},{"type":"text","text":"2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏 C4 的依賴全都消失啦,那麼可以把 C4 放進 queue 裏了:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"queue"}]},{"type":"text","text":" = "},{"type":"codeinline","content":[{"type":"text","text":"[C9, C4]"}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Step6"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後執行 C9,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6e/6e4d3860ceb97fdd6910e2dd011c19a0.gif","alt":"Step6","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Step6"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼 C9 所指的 C7 的入度- 1."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C6C7"},{"type":"text","text":"入度"},{"type":"text","marks":[{"type":"strong"}],"text":"11"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏 C7 的入度並不爲 0,還不能加入 queue,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此時 "},{"type":"codeinline","content":[{"type":"text","text":"queue"}]},{"type":"text","text":" = "},{"type":"codeinline","content":[{"type":"text","text":"[C4]"}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Step7"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着執行 C4,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c9/c96ead904393deb119618989f712b7f8.gif","alt":"Step7","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Step7"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以 C4 所指向的 C6 和 C7 的入度-1,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更新表格:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"bgcolor","attrs":{"color":"#f0f0f0","name":"user"}},{"type":"strong"}],"text":"C6C7"},{"type":"text","text":"入度"},{"type":"text","marks":[{"type":"strong"}],"text":"00"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"C6 和 C7 的入度都變成 0 啦!!把它們放入 queue,繼續執行到直到 queue 爲空即可。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好了,那我們梳理一下這個算法:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"數據結構"},{"type":"text","text":"這裏我們的入度表格可以用 map 來存放,關於 map 還有不清楚的同學可以看之前我寫的 HashMap 的文章哦~"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Map: "}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}}],"text":"但實際代碼中,我們用一個 "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}},{"type":"strong"}],"text":"int array"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"bgcolor","attrs":{"color":"#fff9f9","name":"user"}}],"text":" 來存儲也就夠了,graph node 可以用數組的 index 來表示,value 就用數組裏的數值來表示,這樣比 Map 更精巧。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後用了一個普通的 queue,用來存放可以被執行的那些 node."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"過程"},{"type":"text","text":"我們把入度爲 0 的那些頂點放入 queue 中,然後通過每次執行 queue 中的頂點,就可以讓依賴這個被執行的頂點的那些點的 "},{"type":"codeinline","content":[{"type":"text","text":"入度-1"}]},{"type":"text","text":",如果有頂點的入度變成了 0,就可以放入 queue 了,直到 queue 爲空。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"細節"},{"type":"text","text":"這裏有幾點實現上的細節:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當我們 check 是否有新的頂點的 入度 == 0 時,沒必要過一遍整個 map 或者數組,只需要 check 剛剛改動過的就好了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一個是如果題目沒有給這個圖是 DAG 的條件的話,那麼有可能是不存在可行解的,那怎麼判斷呢?很簡單的一個方法就是比較一下最後結果中的頂點的個數和圖中所有頂點的個數是否相等,或者加個計數器,如果不相等,說明就不存在有效解。所以這個算法也可以用來"},{"type":"text","marks":[{"type":"strong"}],"text":"判斷一個圖是不是有向無環圖"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多題目給的條件可能是給這個圖的 "},{"type":"codeinline","content":[{"type":"text","text":"edge list"}]},{"type":"text","text":",也是表示圖的一種常用的方式。那麼給的這個 "},{"type":"codeinline","content":[{"type":"text","text":"list"}]},{"type":"text","text":" 就是表示圖中的"},{"type":"codeinline","content":[{"type":"text","text":"邊"}]},{"type":"text","text":"。這裏要注意審題哦,看清楚是誰 depends on 誰。其實圖的題一般都不會直接給你這個圖,而是給一個場景,需要你把它變回一個圖。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"時間複雜度"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意 ⚠️:對於圖的時間複雜度分析一定是兩個參數,面試的時候很多同學張口就是 O(n)..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於有 v 個頂點和 e 條邊的圖來說,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一步,預處理得到 map 或者 array,需要過一遍所有的邊纔行,所以是 O(e);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二步,把 入度 == 0 的點入隊出隊的操作是 O(v),如果是一個 DAG,那所有的點都需要入隊出隊一次;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第三步,每次執行一個頂點的時候,要把它指向的那條邊消除了,這個總共執行 e 次;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總:O(v + e)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"空間複雜度"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用了一個數組來存所有點的 indegree,之後的 queue 也是最多把所有的點放進去,所以是 O(v)."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於這課程排序的問題,Leetcode 上有兩道題,一道是 207,問你能否完成所有課程,也就是問拓撲排序是否存在;另一道是 210 題,是讓你返回任意一個拓撲順序,如果不能完成,那就返回一個空 array。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們以 210 這道題來寫,更完整也更常考一些。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d7/d7a9e532ba3c53350ceec70fea27d2aa.jpeg","alt":"Leetcode210","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Leetcode210"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏給的 input 就是我們剛剛說到的 "},{"type":"codeinline","content":[{"type":"text","text":"edge list"}]},{"type":"text","text":"."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Example 1."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Input: 2, [[1,0]]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Output: [0,1]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Explanation: 這裏一共 2 門課,1 的先修課程是 0. 所以正確的選課順序是[0, 1]."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Example 2."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Input: 4, [[1,0],[2,0],[3,1],[3,2]]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Output: [0,1,2,3] or [0,2,1,3]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Explanation:這裏這個例子畫出來如下圖"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/29/299743ac30fa425c5b145eafa94aba6c.jpeg","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Example 3."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Input: 2, [[1,0],[0,1]]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Output: null"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Explanation: 這課沒法上了"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"class"},{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#5c2699","name":"user"}}],"text":"Solution"},{"type":"text","text":" {"}]},{"type":"codeinline","content":[{"type":"text","text":"    "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"public"},{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":"[] findOrder("},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":" numCourses, "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":"[][] prerequisites) {"}]},{"type":"codeinline","content":[{"type":"text","text":"        "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":"[] res = "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"new"},{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":"[numCourses];"}]},{"type":"codeinline","content":[{"type":"text","text":"        "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":"[] indegree = "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"new"},{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":"[numCourses];"}]},{"type":"codeinline"},{"type":"codeinline","content":[{"type":"text","text":"        "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#007400","name":"user"}}],"text":"// get the indegree for each course"}]},{"type":"codeinline","content":[{"type":"text","text":"        "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"for"},{"type":"text","text":"("},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":"[] pre : prerequisites) {"}]},{"type":"codeinline","content":[{"type":"text","text":"            indegree[pre["},{"type":"text","marks":[{"type":"color","attrs":{"color":"#1c00cf","name":"user"}}],"text":"0"},{"type":"text","text":"]] ++;"}]},{"type":"codeinline","content":[{"type":"text","text":"        }"}]},{"type":"codeinline"},{"type":"codeinline","content":[{"type":"text","text":"        "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#007400","name":"user"}}],"text":"// put courses with indegree == 0 to queue"}]},{"type":"codeinline","content":[{"type":"text","text":"        Queue queue = "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"new"},{"type":"text","text":" ArrayDeque<>();"}]},{"type":"codeinline","content":[{"type":"text","text":"        "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"for"},{"type":"text","text":"("},{"type":"text","marks":[{"type":"color","attrs":{"color":"#aa0d91","name":"user"}}],"text":"int"},{"type":"text","text":" i = "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#1c00cf","name":"user"}}],"text":"0"},{"type":"text","text":"; i 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章