Description

給定一個有向圖,每個節點有一個顏色(小寫字母)。找出所有路徑中,單一顏色出現最多次的數量。若圖有環,回傳 -1

Example:

Input: colors = “abaca”, edges = [[0,1],[0,2],[2,3],[3,4]] Output: 3

Intuition#

拓撲排序 + DP,每個節點維護從起點到它的路徑上每種顏色的最大出現次數。

  • 若有環則無限循環,回傳 -1
  • 用拓撲排序保證處理順序
  • 每個節點記錄 26 種顏色各自在到達該節點的所有路徑中出現的最大次數

Approaches#

⭐1: 拓撲排序 + DP#

  • 概念: 用 Kahn 演算法做拓撲排序,同時用 DP 陣列追蹤每種顏色的最大出現次數
  • 時間複雜度: O((V + E) * 26)
  • 空間複雜度: O(V * 26)
class Solution {
    fun largestPathValue(colors: String, edges: Array<IntArray>): Int {
        val n = colors.length
        val graph = Array(n) { mutableListOf<Int>() }
        val inDeg = IntArray(n)

        for ((u, v) in edges) {
            graph[u].add(v)
            inDeg[v]++
        }

        // dp[node][color] = 到達 node 的路徑中 color 的最大出現次數
        val dp = Array(n) { IntArray(26) }
        val queue = ArrayDeque<Int>()

        for (i in 0 until n) {
            if (inDeg[i] == 0) queue.add(i)
        }

        var processed = 0
        var result = 0

        while (queue.isNotEmpty()) {
            val node = queue.removeFirst()
            processed++
            dp[node][colors[node] - 'a']++
            result = maxOf(result, dp[node][colors[node] - 'a'])

            for (next in graph[node]) {
                for (c in 0 until 26) {
                    dp[next][c] = maxOf(dp[next][c], dp[node][c])
                }
                inDeg[next]--
                if (inDeg[next] == 0) queue.add(next)
            }
        }

        return if (processed == n) result else -1
    }
}

2: DFS + 記憶化#

  • 概念: DFS 後序遍歷,用三色標記偵測環,同時計算每個節點的顏色計數
  • 時間複雜度: O((V + E) * 26)
  • 空間複雜度: O(V * 26)
class Solution {
    fun largestPathValue(colors: String, edges: Array<IntArray>): Int {
        val n = colors.length
        val graph = Array(n) { mutableListOf<Int>() }
        for ((u, v) in edges) graph[u].add(v)

        val dp = Array(n) { IntArray(26) { -1 } }
        val state = IntArray(n) // 0: 未訪問, 1: 處理中, 2: 完成
        var result = 0

        fun dfs(node: Int): Boolean {
            if (state[node] == 1) return false // 環
            if (state[node] == 2) return true
            state[node] = 1
            dp[node] = IntArray(26)

            for (next in graph[node]) {
                if (!dfs(next)) return false
                for (c in 0 until 26) {
                    dp[node][c] = maxOf(dp[node][c], dp[next][c])
                }
            }

            dp[node][colors[node] - 'a']++
            result = maxOf(result, dp[node][colors[node] - 'a'])
            state[node] = 2
            return true
        }

        for (i in 0 until n) {
            if (state[i] == 0 && !dfs(i)) return -1
        }
        return result
    }
}

🔑 Takeaways#

  • Pattern: DAG 上的 DP – 拓撲排序確保處理順序,DP 傳遞最優值
  • 關鍵技巧: 每個節點維護 26 種顏色的計數;拓撲排序同時偵測環(processed != n);在加入自身顏色前先傳遞前驅的資訊