---
# System prepended metadata

title: '**Leetcode筆記(Course Schedule II)**'
tags: [值得再想, graph, medium, leetcode]

---

# **Leetcode筆記(Course Schedule II)**


:::info
:information_source: 題目 : Course Schedule II, 類型 : graph , 等級 : medium
日期 : 2023/05/18，2023/07/14，2023/09/04，2023/11/26，2023/12/04，2024/04/04
:::


### 嘗試
2023/07/14
不太確定為什麼錯誤
2023/09/04
主要是需要同時檢查有無重複(visited)，也要排出路徑(重點是有多種可能)，所以也需要另外一個set(done)來記錄，如果已經被放到路徑裡的node，就不用再去查找
```python
class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        graph = defaultdict(list)
        for cour, pre in prerequisites:
            graph[cour].append(pre)
        
        visited, done = set(), set()
        def dfs(cour):
            if cour in visited:
                return False
            # 需要檢查這個cour有沒有已經在路徑裡了
            if not graph[cour] and not cour in done:
                path.append(cour)
                done.add(cour)
                return True
            
            visited.add(cour)

            for pre in graph[cour]:
                if not dfs(pre):
                    return False
            
            # 需要檢查這個cour有沒有已經在路徑裡了
            if not cour in done:
                path.append(cour)
                done.add(cour)
            visited.remove(cour)
            graph[cour] = [] # 加快 已經檢查過了就不用再檢查

            return True


        path = []
        for cour in range(numCourses):
            if not dfs(cour):
                return None
        return path
```
2023/11/26
```python
class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        graph = collections.defaultdict(list)
        for c, p in prerequisites:
            graph[c].append(p)
        
        visited = set() 
        path = list()
        done = set() 

        def dfs(c):
            if c in done:
                return True
            if c in visited:
                return False
            
            visited.add(c)

            for pre in graph[c]:
                if not dfs(pre):
                    return False
            
            path.append(c)
            done.add(c)

            return True

        for c in range(numCourses):
            if not dfs(c):
                return []
        return path
```
2023/12/04
```python
class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        graph = collections.defaultdict(list)
        for c, p in prerequisites:
            graph[c].append(p)
        
        visited, done, res = set(), set(), list()

        def dfs(c):
            if c in done:
                return True
            if c in visited:
                return False
            
            visited.add(c)
            for p in graph[c]:
                if not dfs(p):
                    return False
            
            if c not in done:
                res.append(c)
                done.add(c)
            visited.remove(c)

            return True

        for c in range(numCourses):
            if not dfs(c):
                return None
        return res
```
2024/04/04
```python
class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        record = collections.defaultdict(list)
        for cour, pre in prerequisites:
            record[cour].append(pre)
        
        done = set() # no violation but already added
        res = []
        visited = set()

        def dfs(c):
            if c in done:
                return True
            if c in visited:
                return False

            visited.add(c)
            for pre in record[c]:
                if not dfs(pre):
                    return False
            
            if c not in done:
                res.append(c)
                done.add(c)
            visited.remove(c)

            return True


        for c in range(numCourses):
            if not dfs(c):
                return []
        return res
```


---
### **優化**

時間複雜度：
該算法使用DFS遍歷圖，其中每個節點和邊都只訪問一次。在最壞的情況下，需要遍歷所有的課程節點和它們的先修課程，因此時間複雜度為O(V + E)，其中V是課程節點的數量，E是先修課程的數量。

空間複雜度：
該算法使用了一個記錄先修課程的字典（record），以及一個長度為numCourses的列表（visited）來記錄每個課程的狀態。在最壞的情況下，需要存儲所有的課程和它們的先修課程，因此空間複雜度為O(V + E)，其中V是課程節點的數量，E是先修課程的數量。

```python
class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        record = collections.defaultdict(list)
        for cor, pre in prerequisites:
            record[cor].append(pre)
        
        # -1 : 未上課 / 0 : 上課中 / 1 : 上完課(這條路可行)
        visited = [-1] * numCourses        


        def dfs(c, visited, res):
            # 代表這條路上有一個cor的pre已經被找過了(形成loop)
            if visited[c] == 0:
                return False
            if visited[c] == 1:
                return True

            visited[c] = 0
            for pre in record[c]:
                if not dfs(pre, visited, res):
                    return False
            
            # 代表這個c的pre都可以完成
            visited[c] = 1
            # 最先append的會是最pre的課程
            res.append(c)

            return True


        res = []
        for c in range(numCourses):
            # False : 代表有任一個course的pre無法完成
            if not dfs(c, visited, res):
                return []
        return res
```
---


**:warning: 錯誤語法** 
:::warning

:::


**:thumbsup:學習** 
:::success

:::

**思路**
![](https://hackmd.io/_uploads/r1Zyf2Xrn.png)


**講解連結**
https://www.youtube.com/watch?v=ox6L7Cg0Log&ab_channel=Michelle%E5%B0%8F%E6%A2%A6%E6%83%B3%E5%AE%B6
Provided by. Michelle小梦想家

###### tags: `graph` `medium` `leetcode` `待解`