Skip to content

Commit aee70c6

Browse files
author
Hamid Gasmi
committed
#302: implement DFS solution
1 parent e18162d commit aee70c6

File tree

1 file changed

+82
-21
lines changed

1 file changed

+82
-21
lines changed

09-problems/lc_787_cheapest_flights_within_k_stops.py

+82-21
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
Expected result for K = 4: 6 (4 Stops: C0 --> C3 ---> C1 ---> C4 ---> C2)
2121
2222
2. Intuition:
23-
- Naive:
24-
- Kind of BFS + Optimizations: O(|V|^2 + |V||E|) ?
25-
- to have a variable dst cheapest path price (initialized to Infinity)
26-
- To visit cities multiple-times: when curr visit path price < prev visit path price
27-
- To stop a path if its price > dst cheapest path price
23+
- Kind of BFS + Optimizations: O(|V|^2 + |V||E|) ?
24+
- to have a variable dst cheapest path price (initialized to Infinity)
25+
- To visit cities multiple-times: when curr visit path price < prev visit path price
26+
- To stop a path if its price > dst cheapest path price
27+
- DFS + memoization:
28+
-
2829
- We could do better:
2930
3031
3. Implementation
@@ -36,7 +37,31 @@
3637
"""
3738
from typing import List
3839

39-
class Solution_BFS:
40+
class Solution_Base:
41+
def __init__(self):
42+
self.__max_pirce = 10**8
43+
44+
"""
45+
Time Complexity: O(|E|)
46+
Space Complexity: O(|V| + |E|)
47+
"""
48+
def __build_adjacency_list(self, cities_count: int, edges: List[List[int]]) -> List[List[int]]:
49+
50+
adjacency_list = [ [] for _ in range(cities_count) ]
51+
for [ source, sink, weight ] in edges:
52+
adjacency_list[source].append([ sink, weight ])
53+
54+
return adjacency_list
55+
56+
def __indegree(self, v: int, edges: List[List[int]]) -> int:
57+
indegree = 0
58+
for [ source, sink, weight ] in edges:
59+
if sink == v:
60+
indegree += 1
61+
62+
return indegree
63+
64+
class Solution_BFS(Solution_Base):
4065
'''
4166
Time Complexity: O(|V|^2 + |V||E|) ?
4267
T = T(Build Adjacency List) + T(Kind Of BFS algo)
@@ -51,6 +76,9 @@ def find_cheapest_price(self, cities_count: int, flights: List[List[int]], src:
5176

5277
adjacency_list = self.__build_adjacency_list(cities_count, flights)
5378

79+
if (self.__indegree(dst) == 0):
80+
return -1
81+
5482
'''
5583
Each node (city) is potentially visited multiple times.
5684
Worst case:
@@ -86,22 +114,55 @@ def find_cheapest_price(self, cities_count: int, flights: List[List[int]], src:
86114

87115
return -1 if cheapest_price == self.__max_pirce else cheapest_price
88116

89-
class Solution_Base:
90-
def __init__(self):
91-
self.__max_pirce = 10**8
92-
93-
"""
94-
Time Complexity: O(|E|)
95-
Space Complexity: O(|V| + |E|)
96-
"""
97-
def __build_adjacency_list(self, cities_count: int, flights: List[List[int]]) -> List[List[int]]:
98-
99-
adjacency_list = [ [] for _ in range(cities_count) ]
100-
for [ flight_from, flight_to, flight_pirce ] in flights:
101-
adjacency_list[flight_from].append([ flight_to, flight_pirce ])
102-
103-
return adjacency_list
117+
class Solution_DFS(Solution_Base):
118+
'''
119+
Time Complexity: O(K * |V|^2 + |E|)
120+
T = T(Build Adjacency List) + T(DFS algo)
121+
= O(|E|) + O(K * |V|^2)
122+
123+
Space Complexity: O(K * |V| + |E|)
124+
S = S(Adjacency_list) + S(DFS)
125+
= O(|V| + |E|) + O(K * |V|)
126+
127+
'''
128+
def find_cheapest_price(self, cities_count: int, flights: List[List[int]], src: int, dst: int, max_stops_count: int) -> int:
129+
adjacency_list = self.__build_adjacency_list(cities_count, flights)
104130

131+
if (self.__indegree(dst) == 0):
132+
return -1
133+
134+
'''
135+
Assumption: K < |V|
136+
Time complexity:
137+
depth Nbr of problems work at corresponding depth space at corresponding depth
138+
0 1 1 * O(outdegree(src)) = O(|V|) O(1)
139+
1 |V| |V| * O(|V|) = O(|V|^2) |V| * O(1)
140+
...
141+
K |V| O(|V|^2) O(|V|)
142+
143+
Total time complexity: O(K * |V|^2)
144+
Total space complexity: O(K * |V|)
145+
146+
'''
147+
cheapest_price = self.__dfs(src, dst, adjacency_list, max_stops_count, {})
148+
return -1 if cheapest_price == self.__max_pirce else cheapest_price
149+
150+
def __dfs(self, src: int, dst: int, adjacency_list: List[List[int]], remaining_stops_count: int, memo: dict) -> int:
151+
if src == dst:
152+
return 0
153+
154+
if remaining_stops_count == -1:
155+
return self.__max_pirce
156+
157+
elif (src, remaining_stops_count) in memo:
158+
return memo[(src, remaining_stops_count)]
159+
160+
cheapest_price = self.__max_pirce
161+
for [ flight_to, flight_pirce ] in adjacency_list[src]:
162+
cheapest_price = min(cheapest_price, self.__dfs(flight_to, dst, adjacency_list, remaining_stops_count - 1, memo) + flight_pirce)
163+
164+
memo[(src, remaining_stops_count)] = cheapest_price
165+
return cheapest_price
105166

106167
'''
107168
4

0 commit comments

Comments
 (0)