You are given an array routes
representing bus routes where routes[i]
is a bus route that the ith
bus repeats forever.
routes[0] = [1, 5, 7]
, this means that the 0th
bus travels in the sequence 1 -> 5 -> 7 -> 1 -> 5 -> 7 -> 1 -> ...
forever.You will start at the bus stop source
(You are not on any bus initially), and you want to go to the bus stop target
. You can travel between bus stops by buses only.
Return the least number of buses you must take to travel from source
to target
. Return -1
if it is not possible.
Example 1:
Input: routes = [[1,2,7],[3,6,7]], source = 1, target = 6 Output: 2 Explanation: The best strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6.
Example 2:
Input: routes = [[7,12],[4,5,15],[6],[15,19],[9,12,13]], source = 15, target = 12 Output: -1
Constraints:
1 <= routes.length <= 500
.1 <= routes[i].length <= 105
routes[i]
are unique.sum(routes[i].length) <= 105
0 <= routes[i][j] < 106
0 <= source, target < 106
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach for finding the fewest bus transfers is like trying every possible route from your starting point to your destination. We will explore all combinations of buses to see which one requires the fewest changes. It's inefficient, but guarantees finding the absolute shortest route if one exists.
Here's how the algorithm would work step-by-step:
def bus_routes_brute_force(routes, start_bus_stop, target_bus_stop):
shortest_route = float('inf')
def find_routes(current_stop, current_transfers, visited_routes):
nonlocal shortest_route
if current_stop == target_bus_stop:
shortest_route = min(shortest_route, current_transfers)
return
for route_index, route in enumerate(routes):
if current_stop in route:
# Avoid revisiting routes to prevent infinite loops
if route_index not in visited_routes:
# Explore all stops reachable from the current stop on the same route
for next_stop in route:
new_visited_routes = visited_routes | {route_index}
# Recursively search from this next stop with an increased transfer count
find_routes(next_stop, current_transfers + 1, new_visited_routes)
# Start the search from the initial bus stop with 0 transfers
find_routes(start_bus_stop, -1, set())
if shortest_route == float('inf'):
return -1
return shortest_route
We need to find the fewest buses to get from a starting stop to a destination stop. The core idea is to treat each bus route like a connection and explore routes like how you'd explore a map. We use a technique similar to finding the shortest path to ensure we find the quickest route.
Here's how the algorithm would work step-by-step:
def bus_routes(routes, source, target):
if source == target:
return 0
stop_to_routes = {}
for route_index, route in enumerate(routes):
for stop in route:
if stop not in stop_to_routes:
stop_to_routes[stop] = []
stop_to_routes[stop].append(route_index)
# Keep track of visited routes to avoid cycles.
visited_routes = set()
queue = [(source, 0)]
visited_stops = {source}
while queue:
stop, num_buses = queue.pop(0)
# Explore all routes from the current stop.
for route_index in stop_to_routes.get(stop, []):
if route_index in visited_routes:
continue
visited_routes.add(route_index)
for next_stop in routes[route_index]:
if next_stop == target:
return num_buses + 1
# Only process unvisited stops.
if next_stop not in visited_stops:
visited_stops.add(next_stop)
queue.append((next_stop, num_buses + 1))
return -1
Case | How to Handle |
---|---|
Empty routes array | Return -1 immediately as there are no routes to traverse. |
Source and target are the same bus stop | Return 0 immediately as no bus rides are needed. |
No possible route exists between source and target | Return -1 after BFS completes without finding the target. |
Only one route exists, and it directly connects source and target | The BFS should find the route in the first level and return 1. |
Large number of routes and stops causing potential memory issues | Use efficient data structures (e.g., adjacency lists) to minimize memory footprint. |
Integer overflow with large route or stop numbers | Ensure data types used can accommodate the maximum possible stop and route values or use a different approach. |
A route containing all stops | The algorithm will still process this route correctly, possibly resulting in the shortest path. |
Source or target stop is not present in any of the routes | Return -1 immediately as traversal will be impossible. |