|
| 1 | +# 802. Find Eventual Safe States |
| 2 | + |
| 3 | +There is a directed graph of `n` nodes with each node labeled from `0` to `n - 1`. |
| 4 | +The graph is represented by a 0-indexed 2D integer array `graph` where |
| 5 | +`graph[i]` is an integer array of nodes adjacent to node `i`, |
| 6 | +meaning there is an edge from node `i` to each node in `graph[i]`. |
| 7 | + |
| 8 | +A node is a terminal node if there are no outgoing edges. |
| 9 | +A node is a safe node if every possible path starting from that node leads to a terminal node (or another safe node). |
| 10 | + |
| 11 | +Return an array containing all the safe nodes of the graph. The answer should be sorted in ascending order. |
| 12 | + |
| 13 | +## 基礎思路 |
| 14 | +對於每個 Node 做 DFS,為了減少重複運算,我們用一個 visited 陣列來記錄每個 Node 的狀態,分為三種狀態: |
| 15 | + |
| 16 | +- 0: 未訪問 |
| 17 | +- 1: 訪問中繼點 |
| 18 | +- 2: 安全 |
| 19 | + |
| 20 | +我們只對未訪問的 Node 做 DFS,如果 DFS 過程中遇到訪問中繼點,則表示有環,此 Node 不安全,直接回傳 false,並把該 Node 設為不安全。 |
| 21 | +如果 DFS 過程中沒有遇到不安全的 Node,則會把該 Node 設為安全,表示到達此解點的路徑都是安全的。 |
| 22 | + |
| 23 | +## 解題步驟 |
| 24 | + |
| 25 | +### Step 1: 紀錄 Graph 長度 |
| 26 | + |
| 27 | +```typescript |
| 28 | +const n = graph.length; |
| 29 | +``` |
| 30 | + |
| 31 | +### Step 2: 初始化 visited 陣列 |
| 32 | + |
| 33 | +```typescript |
| 34 | +// 0: 未訪問, 1: 訪問中繼點, 2: 安全 |
| 35 | +const visited = new Array(n).fill(0); |
| 36 | +``` |
| 37 | + |
| 38 | +### Step 3: 定義 DFS 函數 |
| 39 | + |
| 40 | +```typescript |
| 41 | +function dfs(node: number): boolean { |
| 42 | + // 如果該 Node 已經訪問過,則直接回傳該 Node 是否是安全 |
| 43 | + if (visited[node] > 0) { |
| 44 | + return visited[node] === 2; |
| 45 | + } |
| 46 | + |
| 47 | + // 設定該 Node 為訪問中繼點 |
| 48 | + visited[node] = 1; |
| 49 | + |
| 50 | + // 持續檢查下一個 Node 是否安全 |
| 51 | + // Note: 如果陣列是空的,則不會進入迴圈,會直接跳過 for 迴圈 |
| 52 | + for (const next of graph[node]) { |
| 53 | + // 如果下一個 Node 不安全,則設定當前 Node 為不安全 |
| 54 | + if (!dfs(next)) { |
| 55 | + return false; |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + // 設定該 Node 為安全 |
| 60 | + visited[node] = 2; |
| 61 | + return true; |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | +### Step 4: 開始 DFS |
| 66 | + |
| 67 | +```typescript |
| 68 | +// 紀錄結果 |
| 69 | +const result: number[] = []; |
| 70 | + |
| 71 | +// 檢查每個 Node 是否安全 |
| 72 | +for (let i = 0; i < n; i++) { |
| 73 | + // 如果 Node 是安全的,則加入結果中 |
| 74 | + if (dfs(i)) { |
| 75 | + result.push(i); |
| 76 | + } |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +## 時間複雜度 |
| 81 | +- 每個 Node 與 Edge 都只會被訪問一次,所以時間複雜度為 $O(V + E)$ |
| 82 | + |
| 83 | +> $O(V + E)$ |
| 84 | +
|
| 85 | +## 空間複雜度 |
| 86 | +- 額外使用了 visited 陣列,所以空間複雜度為 $O(V)$ |
| 87 | + |
| 88 | +> $O(V)$ |
0 commit comments