Medium草稿★★★★★O(V + E) 時間 · O(V + E) 空間
GraphDFSTopological SortCycle Detection
Patterns📋 拓撲排序🕸️ 圖遍歷・連通分量
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

802Find Eventual Safe StatesGraphsMediumGraphs

在有向圖中,從某節點出發,若無論走哪條路徑最終都會到達終端節點(出度為 0),則該節點是安全節點。回傳所有安全節點(升序排列)。

Example:

Input: graph = [[1,2],[2,3],[5],[0],[5],[],[]] Output: [2,4,5,6]

Intuition

TIP

安全節點 = 不在任何環上的節點。用 DFS 標記環上節點,或用反向拓撲排序。

Approaches

1. DFS Three-Color Marking — O(V + E) / O(V)
  • Idea: 用三種狀態(未訪問/處理中/安全)做 DFS。若 DFS 遇到「處理中」節點代表有環,該路徑上的節點不安全。
  • Time: O(V + E)
  • Space: O(V)
class Solution {
    fun eventualSafeNodes(graph: Array<IntArray>): List<Int> {
        val n = graph.size
        // 0: 未訪問, 1: 處理中, 2: 安全
        val state = IntArray(n)

        fun dfs(node: Int): Boolean {
            if (state[node] != 0) return state[node] == 2
            state[node] = 1
            for (next in graph[node]) {
                if (!dfs(next)) return false
            }
            state[node] = 2
            return true
        }

        return (0 until n).filter { dfs(it) }
    }
}
⭐ 2. Reverse-Graph Topological Sort — O(V + E) / O(V + E)
  • Idea: 建立反向圖,從終端節點(原圖出度 0)開始拓撲排序,能被處理到的節點都是安全的
  • Time: O(V + E)
  • Space: O(V + E)
class Solution {
    fun eventualSafeNodes(graph: Array<IntArray>): List<Int> {
        val n = graph.size
        val outDeg = IntArray(n)
        val reverseGraph = Array(n) { mutableListOf<Int>() }

        for (u in 0 until n) {
            for (v in graph[u]) {
                reverseGraph[v].add(u)
            }
            outDeg[u] = graph[u].size
        }

        val queue = ArrayDeque<Int>()
        for (i in 0 until n) {
            if (outDeg[i] == 0) queue.add(i)
        }

        val safe = BooleanArray(n)
        while (queue.isNotEmpty()) {
            val node = queue.removeFirst()
            safe[node] = true
            for (prev in reverseGraph[node]) {
                outDeg[prev]--
                if (outDeg[prev] == 0) queue.add(prev)
            }
        }

        return (0 until n).filter { safe[it] }
    }
}

🔑 Takeaways