Problem
You are given an undirected weighted graph of n
nodes (0-indexed), represented by an edge list where edges[i] = [a, b]
is an undirected edge connecting the nodes a
and b
with a probability of success of traversing that edge succProb[i]
.
Given two nodes start
and end
, find the path with the maximum probability of success to go from start
to end
and return its success probability.
If there is no path from start
to end
, return 0. Your answer will be accepted if it differs from the correct answer by at most 1e-5.
Examples
Example 1:
graph TD 0([0]) ---|0.5| 1([1]) 1 ---|0.5| 2([2]) 0 ---|0.2| 2 style 0 fill:#f96,stroke:#f66,stroke-width:2px; style 2 fill:#9f9,stroke:#0f0,stroke-width:2px;
Input: n = 3, edges =[[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2
Output: 0.25000
Explanation: There are two paths from start to end, one having a probability of success = 0.2 and the other has 0.5 * 0.5 = 0.25.
Example 2:
graph TD 0([0]) ---|0.5| 1([1]) 1 ---|0.5| 2([2]) 0 ---|0.3| 2 style 0 fill:#f96,stroke:#f66,stroke-width:2px; style 2 fill:#9f9,stroke:#0f0,stroke-width:2px;
Input: n = 3, edges =[[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2
Output: 0.30000
Example 3:
graph TD 0([0]) ---|0.5| 1([1]) 2([2]) style 0 fill:#f96,stroke:#f66,stroke-width:2px; style 2 fill:#9f9,stroke:#0f0,stroke-width:2px;
Input: n = 3, edges =[[0,1]], succProb = [0.5], start = 0, end = 2
Output: 0.00000
Explanation: There is no path between 0 and 2.
Solution
Method 1 - Using Dijkstra Algorithm with PriorityQueue
The approach in Java will be similar to the Python solution, using Dijkstra’s algorithm adapted for finding the max probability path. Here’s how you can implement it:
- Graph Representation: Use an adjacency list.
- Priority Queue: Use a priority queue to maintain nodes sorted by their maximum probability path.
- Relaxation: Update probabilities and push the node to the queue if a higher probability path is found.
- Termination Check: Return the probability once the
end
node is reached; otherwise, return 0 if no path exists.
Video Explanation
Here is the video explanation of the approach below:
Code
Java
public class Solution {
static class ProbabilityEdge {
int vertex;
double probability;
ProbabilityEdge(int vertex, double probability) {
this.vertex = vertex;
this.probability = probability;
}
}
public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
// Step 1: Create the graph
Map<Integer, List<ProbabilityEdge>> gr = new HashMap<>();
for (int i = 0; i < edges.length; i++) {
int[] edge = edges[i];
int u = edge[0];
int v = edge[1];
double prob = succProb[i];
gr.putIfAbsent(u, new ArrayList<>());
gr.putIfAbsent(v, new ArrayList<>());
gr.get(u).add(new ProbabilityEdge(v, prob));
gr.get(v).add(new ProbabilityEdge(u, prob));
}
// Step 2: Use a priority queue (max-heap)
PriorityQueue<ProbabilityEdge> pq = new PriorityQueue<>((a, b) -> Double.compare(b.probability, a.probability));
pq.add(new ProbabilityEdge(start, 1.0));
double[] maxProb = new double[n];
maxProb[start] = 1.0;
while (!pq.isEmpty()) {
// Step 3: Get the ProbabilityEdge with the highest probability
ProbabilityEdge current = pq.poll();
int node = current.vertex;
double prob = current.probability;
// Step 4: If we reached the end ProbabilityEdge, return the
// probability
if (node == end) {
return prob;
}
// Step 5: Relax edges
for (ProbabilityEdge nei : gr.getOrDefault(node, new ArrayList<>())) {
int nextNode = nei.vertex;
double edgeProb = nei.probability;
double newProb = prob * edgeProb;
if (newProb > maxProb[nextNode]) {
maxProb[nextNode] = newProb;
pq.add(new ProbabilityEdge(nextNode, newProb));
}
}
}
// If we exhaust the queue without finding the end ProbabilityEdge
return 0.0;
}
}
Python
import heapq
def maxProbability(n, edges, succProb, start, end):
# Step 1: Create the graph
graph = [[] for _ in range(n)]
for (a, b), prob in zip(edges, succProb):
graph[a].append((b, prob))
graph[b].append((a, prob))
# Step 2: Use a max-heap (in Python, we use a min-heap with negative probabilities)
max_heap = [(-1.0, start)] # (-prob, node)
max_prob = [0.0] * n
max_prob[start] = 1.0
while max_heap:
# Step 3: Get the node with the highest probability
prob, node = heapq.heappop(max_heap)
prob = -prob
# Step 4: If we reached the end node, return the probability
if node == end:
return prob
# Step 5: Relax edges
for neighbor, edge_prob in graph[node]:
new_prob = prob * edge_prob
if new_prob > max_prob[neighbor]:
max_prob[neighbor] = new_prob
heapq.heappush(max_heap, (-new_prob, neighbor))
# If we exhaust the queue without finding the end node
return 0.0
Complexity
- ⏰ Time complexity:
O(E log V)
, whereE
is number of edges, andV
is number of nodes or vertices.- It takes
O(E)
time to build graph - Inserting 1 element in PQ takes
O(log V)
time, and each node can be inserted multiple times, which is proportional toE
times, hence takesO((E)logV)
times
- It takes
- 🧺 Space complexity:
O(E+V)
- priority queue will store all nodes, and each node might be added more than once but at most
O(V)
elements will be in the queue at any time. maxProb
array takesO(V)
space- Graph storage requires
O(E+V)
space
- priority queue will store all nodes, and each node might be added more than once but at most
Method 2 - Using Dijkstra Algorithm closer to BFS
Code
Java
class Solution {
static class ProbabilityEdge {
int vertex;
double prob;
ProbabilityEdge(int vertex, double prob) {
this.vertex = vertex;
this.prob = prob;
}
}
public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
Map<Integer, List<ProbabilityEdge>> gr = new HashMap<>();
for (int i = 0; i < edges.length; ++i) {
int[] edge = edges[i];
int u = edge[0];
int v = edge[1];
double prob = succProb[i];
gr.putIfAbsent(u, new ArrayList<>());
gr.putIfAbsent(v, new ArrayList<>());
gr.get(u).add(new ProbabilityEdge(v, prob));
gr.get(v).add(new ProbabilityEdge(u, prob));
}
double[] probs = new double[n]; // best prob so far for each node
Queue<ProbabilityEdge> queue = new LinkedList<>();
queue.add(new ProbabilityEdge(start, 1.0));
while (!queue.isEmpty()) {
ProbabilityEdge curr = queue.poll();
int parent = curr.vertex;
double prob = curr.prob;
for (ProbabilityEdge nei : gr.getOrDefault(parent, new ArrayList<>())) {
// add to queue only if: it can make a better prob
double newProb = prob * nei.prob;
if (probs[nei.vertex] >= newProb) {
continue;
}
queue.add(new ProbabilityEdge(nei.vertex, newProb));
probs[nei.vertex] = newProb;
}
}
return probs[end];
}
}