Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit eca482d

Browse files
committed
1514-path-with-maximum-probability.md Added Python solution.
1 parent b9ecf44 commit eca482d

File tree

8 files changed

+461
-0
lines changed

8 files changed

+461
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,6 @@ You can skip the more difficult problems and do them later.
114114
- [685. Redundant Connection II](en/1-1000/685-redundant-connection-ii.md) was solved in _Python_.
115115
- [1584. Min Cost to Connect All Points](en/1001-2000/1584-min-cost-to-connect-all-points.md) was solved in _Python, Java, C++, JavaScript, C#, Go, Ruby_ and 2 ways.
116116
- [207. Course Schedule](en/1-1000/207-course-schedule.md) was solved in _Python, Java, C++, C#_ and 2 ways.
117+
- [1514. Path with Maximum Probability](en/1001-2000/1514-path-with-maximum-probability.md) was solved in _Python_ and 2 ways.
117118

118119
More LeetCode problems will be added soon...
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# 1514. Path with Maximum Probability - Best Practices of LeetCode Solutions
2+
LeetCode link: [1514. Path with Maximum Probability](https://leetcode.com/problems/path-with-maximum-probability), difficulty: **Medium**.
3+
4+
## LeetCode description of "1514. Path with Maximum Probability"
5+
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]`.
6+
7+
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.
8+
9+
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**.
10+
11+
### [Example 1]
12+
![](../../images/examples/1514_1.png)
13+
14+
**Input**: `n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2`
15+
16+
**Output**: `0.25000`
17+
18+
**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.`
19+
20+
### [Example 2]
21+
![](../../images/examples/1514_2.png)
22+
23+
**Input**: `n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2`
24+
25+
**Output**: `0.30000`
26+
27+
### [Example 3]
28+
![](../../images/examples/1514_3.png)
29+
30+
**Input**: `n = 3, edges = [[0,1]], succProb = [0.5], start = 0, end = 2`
31+
32+
**Output**: `0.00000`
33+
34+
**Explanation**: `There is no path between 0 and 2.`
35+
36+
### [Constraints]
37+
- `2 <= n <= 10^4`
38+
- `0 <= start, end < n`
39+
- `start != end`
40+
- `0 <= a, b < n`
41+
- `a != b`
42+
- `0 <= succProb.length == edges.length <= 2*10^4`
43+
- `0 <= succProb[i] <= 1`
44+
- There is at most one edge between every two nodes.
45+
46+
### [Hints]
47+
<details>
48+
<summary>Hint 1</summary>
49+
Multiplying probabilities will result in precision errors.
50+
</details>
51+
52+
<details>
53+
<summary>Hint 2</summary>
54+
Take log probabilities to sum up numbers instead of multiplying them.
55+
</details>
56+
57+
<details>
58+
<summary>Hint 3</summary>
59+
Use Dijkstra's algorithm to find the minimum path between the two nodes after negating all costs.
60+
</details>
61+
62+
## Intuition
63+
We can use **Dijkstra's algorithm**.
64+
65+
![](../../images/graph_Dijkstra_algorithm_animation.gif)
66+
67+
This animation is about **Dijkstra's algorithm** to find the shortest path between `a` and `b`.
68+
It picks the unvisited vertex with the lowest distance, calculates the distance through it to each unvisited neighbor, and updates the neighbor's distance if smaller. Mark **visited** (set to red) when done with neighbors.
69+
70+
In short, **Dijkstra's algorithm** means **to find the nearest point and walk through it, and never go back. Repeatedly**.
71+
72+
## Complexity
73+
**V**: vertex count, **E**: Edge count.
74+
75+
### Dijkstra's algorithm without using `heap sort`
76+
* Time: `O(V * V)`.
77+
* Space: `O(V + E)`.
78+
79+
### Dijkstra's algorithm using `heap sort`
80+
* Time: `O(E * log(E))`.
81+
* Space: `O(V + E)`.
82+
83+
## Python
84+
### Dijkstra's algorithm without using `heap sort`
85+
The code will time out when executed on LeetCode, but this is not a problem with the code itself. The `heap sort` implementation below will not time out.
86+
```python
87+
class Solution:
88+
def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float:
89+
node_to_pairs = defaultdict(set)
90+
91+
for i, (source_node, target_node) in enumerate(edges):
92+
node_to_pairs[source_node].add((target_node, succ_prob[i]))
93+
node_to_pairs[target_node].add((source_node, succ_prob[i]))
94+
95+
max_probabilities = [0] * n
96+
max_probabilities[start_node] = 1
97+
visited = [False] * n
98+
99+
for _ in range(n - 1):
100+
current_node = None
101+
maximum_probability = 0
102+
103+
for node, probability in enumerate(max_probabilities):
104+
if not visited[node] and probability > maximum_probability:
105+
maximum_probability = probability
106+
current_node = node
107+
108+
if current_node is None:
109+
break
110+
111+
visited[current_node] = True
112+
113+
for target_node, probability in node_to_pairs[current_node]:
114+
probability_ = probability * max_probabilities[current_node]
115+
116+
if probability_ > max_probabilities[target_node]:
117+
max_probabilities[target_node] = probability_
118+
119+
return max_probabilities[end_node]
120+
```
121+
122+
### Dijkstra's algorithm using `heap sort`
123+
#### 1. `heap sort` without using `visited`
124+
```python
125+
import heapq
126+
127+
class Solution:
128+
def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float:
129+
node_to_pairs = defaultdict(set)
130+
131+
for i, (source_node, target_node) in enumerate(edges):
132+
node_to_pairs[source_node].add((target_node, succ_prob[i]))
133+
node_to_pairs[target_node].add((source_node, succ_prob[i]))
134+
135+
max_probabilities = [0 for node in range(n)]
136+
max_probabilities[start_node] = 1
137+
items = [(-1, start_node)]
138+
139+
while items:
140+
current_probability, current_node = heapq.heappop(items)
141+
142+
if current_node == end_node:
143+
return -current_probability
144+
145+
for target_node, probability in node_to_pairs[current_node]:
146+
probability_ = abs(current_probability) * probability
147+
148+
if probability_ > max_probabilities[target_node]:
149+
max_probabilities[target_node] = probability_
150+
# It may cause the same `target_node` added into `items` more than once, but it doesn't matter. Because only the one `heappush`ed first may change the `max_probabilities` data.
151+
heapq.heappush(items, (-probability_, target_node))
152+
153+
return 0
154+
```
155+
156+
#### 2. `heap sort` using `visited`
157+
```python
158+
import heapq
159+
160+
class Solution:
161+
def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float:
162+
node_to_pairs = defaultdict(set)
163+
164+
for i, (source_node, target_node) in enumerate(edges):
165+
node_to_pairs[source_node].add((target_node, succ_prob[i]))
166+
node_to_pairs[target_node].add((source_node, succ_prob[i]))
167+
168+
max_probabilities = [0 for node in range(n)]
169+
max_probabilities[start_node] = 1
170+
items = [(-1, start_node)]
171+
visited = [False] * n # added 1
172+
173+
while items:
174+
current_probability, current_node = heapq.heappop(items)
175+
176+
if current_node == end_node:
177+
return -current_probability
178+
179+
if visited[current_node]: # added 3
180+
continue
181+
182+
visited[current_node] = True # added 2
183+
184+
for target_node, probability in node_to_pairs[current_node]:
185+
if visited[target_node]: # added 4
186+
continue
187+
188+
probability_ = abs(current_probability) * probability
189+
190+
if probability_ > max_probabilities[target_node]:
191+
max_probabilities[target_node] = probability_
192+
# It may cause the same `target_node` added into `items` more than once, but it doesn't matter. Because only the one `heappush`ed first may change the `max_probabilities` data.
193+
heapq.heappush(items, (-probability_, target_node))
194+
195+
return 0
196+
```
197+
198+
## JavaScript
199+
```javascript
200+
// Welcome to create a PR to complete the code of this language, thanks!
201+
```
202+
203+
## Java
204+
```java
205+
// Welcome to create a PR to complete the code of this language, thanks!
206+
```
207+
208+
## C++
209+
```cpp
210+
// Welcome to create a PR to complete the code of this language, thanks!
211+
```
212+
213+
## C#
214+
```c#
215+
// Welcome to create a PR to complete the code of this language, thanks!
216+
```
217+
218+
## Go
219+
```go
220+
// Welcome to create a PR to complete the code of this language, thanks!
221+
```
222+
223+
## Ruby
224+
```ruby
225+
# Welcome to create a PR to complete the code of this language, thanks!
226+
```
227+
228+
## C, Kotlin, Swift, Rust or other languages
229+
```
230+
// Welcome to create a PR to complete the code of this language, thanks!
231+
```

images/examples/1514_1.png

6.25 KB
Loading

images/examples/1514_2.png

6.4 KB
Loading

images/examples/1514_3.png

4.62 KB
Loading

images/examples/743_1.png

7.38 KB
Loading
8.84 KB
Loading

0 commit comments

Comments
 (0)