Medium草稿★★★★★O(E log V) 時間 · O(V + E) 空間
GraphDijkstraBellman-FordHeapShortest Path
Patterns🛣️ 帶權最短路⛰️ 堆・Top-K🕸️ 圖遍歷・連通分量
尚未複習過

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

1514Path with Maximum ProbabilityAdvanced GraphsMediumAdvanced Graphs

給定一個無向加權圖,邊的權重是成功通過的機率。求從 startend 的最大成功機率路徑。若不可達回傳 0

Example:

Input: n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2 Output: 0.25

Intuition

TIP

最大機率路徑 = 最短路徑的變體,用最大堆的 Dijkstra,乘積替代加法。

Approaches

1. Bellman-Ford — O(V * E) / O(V)
  • Idea: 用 Bellman-Ford 反覆鬆弛所有邊,找最大機率
  • Time: O(V * E)
  • Space: O(V)
class Solution {
    fun maxProbability(n: Int, edges: Array<IntArray>, succProb: DoubleArray, start: Int, end: Int): Double {
        val prob = DoubleArray(n)
        prob[start] = 1.0

        repeat(n - 1) {
            var updated = false
            for (i in edges.indices) {
                val (u, v) = edges[i]
                val p = succProb[i]
                if (prob[u] * p > prob[v]) {
                    prob[v] = prob[u] * p
                    updated = true
                }
                if (prob[v] * p > prob[u]) {
                    prob[u] = prob[v] * p
                    updated = true
                }
            }
            if (!updated) return@repeat
        }
        return prob[end]
    }
}
⭐ 2. Dijkstra (max-heap) — O(E log V) / O(V + E)
  • Idea: 用最大堆的 Dijkstra,每次取出機率最大的節點,更新鄰居機率
  • Time: O(E log V)
  • Space: O(V + E)
class Solution {
    fun maxProbability(n: Int, edges: Array<IntArray>, succProb: DoubleArray, start: Int, end: Int): Double {
        val graph = Array(n) { mutableListOf<Pair<Int, Double>>() }
        for (i in edges.indices) {
            val (u, v) = edges[i]
            graph[u].add(v to succProb[i])
            graph[v].add(u to succProb[i])
        }

        val prob = DoubleArray(n)
        prob[start] = 1.0
        val pq = java.util.PriorityQueue<Pair<Int, Double>>(compareByDescending { it.second })
        pq.add(start to 1.0)

        while (pq.isNotEmpty()) {
            val (node, p) = pq.poll()
            if (node == end) return p
            if (p < prob[node]) continue

            for ((next, edgeProb) in graph[node]) {
                val newProb = p * edgeProb
                if (newProb > prob[next]) {
                    prob[next] = newProb
                    pq.add(next to newProb)
                }
            }
        }
        return 0.0
    }
}

🔑 Takeaways