現在你總共有 n 門課需要選,記為 0 到 n-1。
在選修某些課程之前需要一些先修課程。 例如,想要學習課程 0 ,你需要先完成課程 1 ,我們用乙個匹配來表示他們: [0,1]
給定課程總量以及它們的先決條件,返回你為了學完所有課程所安排的學習順序。
可能會有多個正確的順序,你只要返回一種就可以了。如果不可能完成所有課程,返回乙個空陣列。
輸入: 2, [[1,0]]輸出: [0,1]
解釋: 總共有 2 門課程。要學習課程 1,你需要先完成課程 0。因此,正確的課程順序為 [0,1] 。
輸入: 4, [[1,0],[2,0],[3,1],[3,2]]參考官方題解方法二:廣度優先搜尋輸出: [0,1,2,3] or [0,2,1,3]
解釋: 總共有 4 門課程。要學習課程 3,你應該先完成課程 1 和課程 2。並且課程 1 和課程 2 都應該排在課程 0 之後。
因此,乙個正確的課程順序是 [0,1,2,3] 。另乙個正確的排序是 [0,2,1,3] 。
在這份題解中,給出了bfs和dfs兩種方法。我自己想的時候也的確想到了bfs中利用棧來得到結果。但是dfs在寫的過程中需要標記節點的狀態有三種,明顯比bfs複雜;而且兩個方法的時間複雜度、空間複雜度又都是o(m+n)(其中 n 為課程數,m 為先修課程的要求數)所以直接選擇bfs。先記住一種好記的,二刷再記更多解法。
簡單概括一下下bfs的解法(和第一篇【每日一題】二叉樹層序遍歷其實是乙個模板):
為每個節點記錄入度,入度為0的就是不需要先修課的課程,直接放進佇列,並把這些節點與其相鄰節點斷開(相鄰節點入度-1);
從佇列左側取出乙個點放入答案列表,並遍歷它的相鄰節點,其中有入度為0的依舊入隊;
bfs結束之後,如果答案列表長度等於所有課程數,說明沒有環,完;小於,則有環,返回空列表。
class
solution
:def
findorder
(self, numcourses:
int, prerequisites: list[list[
int]])
-> list[
int]
: edges = collections.defaultdict(
list
)#存圖
indeg =[0
]* numcourses #入度
result =
list()
#存結果
for info in prerequisites:
edges[info[1]
]0])
#連圖 indeg[info[0]
]+=1#初始化入度值
#把所有入度為0的邊放入佇列
q = collections.deque(
[u for u in
range
(numcourses)
if indeg[u]==0
])while q:
u = q.popleft(
)#取出隊首點
#放入結果列表
for v in edges[u]
:
indeg[v]-=1
if indeg[v]==0
:iflen(result)
!= numcourses:
#數目不符則返回空列表
result =
list()
return result
語法方面,collections.defaultdict(list)可以很容易將鍵-值對序列轉換為列表字典(參考collections.defaultdict()的使用)。 每日一題 LeetCode
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。示例 1 輸入 7,5,6,4 輸出 5 限制 0 陣列長度 50000 思想是 分治演算法 所有的 逆序對 於 3 個部分 左邊區間的逆序對 右邊區間的逆序對 橫跨兩個區間的...
LeetCode每日一題(題1028)
最近在刷leetcode每日一題,每次做完之後總能有些收穫,所以想著不如每天寫個部落格記錄一下做的題目的解法以及自己寫的時候問題出在 從先序遍歷還原二叉樹 題目大意 給出乙個字串 1 2 3 4 5 6 7 1代表節點的值,前面的 個數代表節點的深度。如果只有乙個子節點,保證這個節點為左子節點。返回...
LeetCode每日一題(題139)
題目 題目大意 給出乙個字串s和乙個字串陣列words,判斷s是否能夠拆分成多個words中的字串。分析 這道題比較簡單的方式應該是採用動態規劃來做。對於任意乙個字串中的區間,可以判斷該區間組成的字串是否在字典中,如果是,則這個區間的真假取決於前面那個區間的真假。給出狀態轉移方程dp i dp j ...