Bus Routes

Nov. 12, 2023, 6 p.m.

This post details my solution to the Bus Stops leetcode challenge

Intuition

My initial thoughts to solving this problem was to use a modified version of Dijkstra's algorithm. This way the shortest amount of buses can be found quickly and efficiently.

Approach

After yesterday's challenge creating a basic Dijkstra's algorithm in Python was pretty simple. However, instead of using nodes to edges where the edges are potential nodes to visit, nodes were instead buses and the edges were stops. This meant that an exact lookup was needed to confirm that the current bus stops at a stop within the potential bus' path. Obviously, we don't need to be getting on the same bus twice so each time a new bus is boarded, we add it to a seen set preventing it from being checked again.

To implement the modified version of Dijkstra's algorithm, I utilized a dictionary of sets where the key was the bus and the set was the potential stops. As the time spent on the bus doesn't matter, a simple intersection can be performed on the set to confirm that the bus shares stops with another bus. Additionally, this means that if the target is in the current set, the distance value can just be returned as there will only ever be more bus changes after the first bus contains the target stop.

Complexity

Time complexity

The time complexity of this solution is O(N * M) where N is the number of buses and M is the average number of stops.

Space complexity

The space complexity of this solution is O(N * M) where N is the number of buses and M is the average number of stops.

Code


class Solution:
    def numBusesToDestination(self, routes: List[List[int]], source: int, target: int) -> int:
        if source == target:
            return 0
        buses = {}
        for x in range(len(routes)):
            buses[x] = set(routes[x])
        queue = []
        for stops in buses.values():
            if source in stops:
                queue.append((1, stops))
        seen = set()
        while queue:
            distance, bus_stops = queue.pop(0)
            if target in bus_stops:
                return distance
            for x in range(len(routes)):
                if x not in seen and bus_stops.intersection(buses[x]):
                    seen.add(x)
                    queue.append((distance + 1, buses[x]))
        return -1