hard Bus Routes
Problem Statement
You are given an array routes where routes[i] is the list of bus stops that the ithe bus travels in a cyclic manner. For example, if routes[0] = [2, 3, 7], it means that bus 0 travels through the stops 2 -> 3 -> 7 -> 2 -> 3 -> 7 ... and then repeats this sequence indefinitely.
You start at a bus stop called source and wish to travel to a bus stop called target using the bus routes. You can switch buses at any bus stop that is common to the routes of two buses.
Return the minimum number of buses you need to take to travel from source to target. If it is not possible to reach the target, return -1.
Examples
Example 1
- Input: routes =
[[2, 3, 4], [5, 6, 7, 8], [4, 5, 9, 10], [10, 12]], source =3, target =12 - Expected Output:
3 - Justification: Start at stop
3, take bus0to stop4, switch to bus2to reach stop10, and then take bus3to reach to12. You need 3 buses.
Example 2
- Input: routes =
[[1, 2, 3, 4, 5], [5, 6, 7, 8], [8, 9, 10, 11]], source =1, target =11 - Expected Output:
3 - Justification: Start at stop
1, take bus0to stop5, switch to bus1to reach stop8, then switch to bus2to reach stop11. You need 3 buses.
Example 3
- Input: routes =
[[1, 2, 5], [3, 6, 7], [7, 9, 10]], source =2, target =10 - Expected Output:
-1 - Justification: It is not possible to reach from bus stop
2to10.
Constraints:
- 1 <= routes.length <= 500.
- 1 <= routes[i].length <= 105
- All the values of routes[i] are unique.
- sum(routes[i].length) <= 105
- 0 <= routes[i][j] < 106
- 0 <= source, target < 106
Try it yourself
Try solving this question here:
✅ Solution Bus Routes
Problem Statement
You are given an array routes where routes[i] is the list of bus stops that the ithe bus travels in a cyclic manner. For example, if routes[0] = [2, 3, 7], it means that bus 0 travels through the stops 2 -> 3 -> 7 -> 2 -> 3 -> 7 ... and then repeats this sequence indefinitely.
You start at a bus stop called source and wish to travel to a bus stop called target using the bus routes. You can switch buses at any bus stop that is common to the routes of two buses.
Return the minimum number of buses you need to take to travel from source to target. If it is not possible to reach the target, return -1.
Examples
Example 1
- Input: routes =
[[2, 3, 4], [5, 6, 7, 8], [4, 5, 9, 10], [10, 12]], source =3, target =12 - Expected Output:
3 - Justification: Start at stop
3, take bus0to stop4, switch to bus2to reach stop10, and then take bus3to reach to12. You need 3 buses.
Example 2
- Input: routes =
[[1, 2, 3, 4, 5], [5, 6, 7, 8], [8, 9, 10, 11]], source =1, target =11 - Expected Output:
3 - Justification: Start at stop
1, take bus0to stop5, switch to bus1to reach stop8, then switch to bus2to reach stop11. You need 3 buses.
Example 3
- Input: routes =
[[1, 2, 5], [3, 6, 7], [7, 9, 10]], source =2, target =10 - Expected Output:
-1 - Justification: It is not possible to reach from bus stop
2to10.
Constraints:
- 1 <= routes.length <= 500.
- 1 <= routes[i].length <= 105
- All the values of routes[i] are unique.
- sum(routes[i].length) <= 105
- 0 <= routes[i][j] < 106
- 0 <= source, target < 106
Solution
To solve this problem, we can use the Breadth-First Search (BFS) algorithm. The problem requires us to find the shortest path in terms of bus transfers from the source to the target stop. BFS is suitable because it explores all possible routes level by level, ensuring that we find the shortest path first.
We'll start from the source stop and explore all buses that can be taken from there. For each bus, we'll check all stops it visits and mark them as visited to avoid reprocessing. We'll then repeat this process for each newly reached stop until we reach the target stop or exhaust all possibilities. This ensures that we find the minimum number of bus transfers needed to reach the target.
Step-by-step Algorithm
-
Initialization:
- Create a map
stopToBuseswhere the key is a bus stop and the value is a list of buses that visit this stop. - Initialize an empty queue for BFS,
queue, which will store pairs of (current_stop, buses_taken). - Initialize a set
visitedStopsto keep track of bus stops that have been visited. - Initialize a set
usedBusesto keep track of buses that have been used.
- Create a map
-
Building the
stopToBusesMap:- For each bus route in
routes, and for each stop in that route, add the bus index to the list of buses in thestopToBusesmap for that stop.
- For each bus route in
-
Start BFS:
- Enqueue the
sourcestop with 0 buses taken (queue.offer(new int[]{source, 0})). - Mark the
sourcestop as visited (visitedStops.add(source)).
- Enqueue the
-
Processing the Queue:
- While the queue is not empty:
- Dequeue the front element from the queue to get the current stop and the number of buses taken so far.
- For each bus that visits the current stop:
- If the bus has already been used, skip it.
- Mark the bus as used (
usedBuses.add(bus)). - For each stop that this bus visits:
- If this stop is the
target, return the number of buses taken plus one. - If this stop has not been visited yet, mark it as visited and enqueue it with the number of buses taken plus one.
- If this stop is the
- While the queue is not empty:
-
If Target Not Reached:
- If the queue is empty and the target has not been reached, return -1.
Algorithm Walkthrough
Input:
- routes:
[[2, 3, 4], [5, 6, 7, 8], [4, 5, 9, 10], [10, 12]] - source:
3 - target:
12
-
Initialization:
stopToBusesmap:{}initially.queue:[]visitedStops:{}usedBuses:{}
-
Building the
stopToBusesMap:- Final
stopToBusesmap:{2: [0], 3: [0], 4: [0, 2], 5: [1, 2], 6: [1], 7: [1], 8: [1], 9: [2], 10: [2, 3], 12: [3]}
- Final
-
Start BFS:
- Enqueue (3, 0):
queue = [(3, 0)] - Mark 3 as visited:
visitedStops = {3}
- Enqueue (3, 0):
-
Processing the Queue:
- Dequeue (3, 0):
current_stop = 3,buses_taken = 0- Buses visiting stop 3:
[0]- Bus 0:
- Stops visited by bus 0:
[2, 3, 4] - Stop 2:
- Not the target, mark visited and enqueue:
queue = [(2, 1)],visitedStops = {2, 3}
- Not the target, mark visited and enqueue:
- Stop 3:
- Already visited, skip.
- Stop 4:
- Not the target, mark visited and enqueue:
queue = [(2, 1), (4, 1)],visitedStops = {2, 3, 4}
- Not the target, mark visited and enqueue:
- Stops visited by bus 0:
- Bus 0:
- Buses visiting stop 3:
- Dequeue (2, 1):
current_stop = 2,buses_taken = 1- Buses visiting stop 2:
[0](already used, skip)
- Buses visiting stop 2:
- Dequeue (4, 1):
current_stop = 4,buses_taken = 1- Buses visiting stop 4:
[0, 2]- Bus 0:
- Already used, skip.
- Bus 2:
- Stops visited by bus 2:
[4, 5, 9, 10] - Stop 4:
- Already visited, skip.
- Stop 5:
- Not the target, mark visited and enqueue:
queue = [(5, 2)],visitedStops = {2, 3, 4, 5}
- Not the target, mark visited and enqueue:
- Stop 9:
- Not the target, mark visited and enqueue:
queue = [(5, 2), (9, 2)],visitedStops = {2, 3, 4, 5, 9}
- Not the target, mark visited and enqueue:
- Stop 10:
- Not the target, mark visited and enqueue:
queue = [(5, 2), (9, 2), (10, 2)],visitedStops = {2, 3, 4, 5, 9, 10}
- Not the target, mark visited and enqueue:
- Stops visited by bus 2:
- Bus 0:
- Buses visiting stop 4:
- Dequeue (5, 2):
current_stop = 5,buses_taken = 2- Buses visiting stop 5:
[1, 2]- Bus 1:
- Stops visited by bus 1:
[5, 6, 7, 8] - Stop 5:
- Already visited, skip.
- Stop 6:
- Not the target, mark visited and enqueue:
queue = [(9, 2), (10, 2), (6, 3)],visitedStops = {2, 3, 4, 5, 6, 9, 10}
- Not the target, mark visited and enqueue:
- Stop 7:
- Not the target, mark visited and enqueue:
queue = [(9, 2), (10, 2), (6, 3), (7, 3)],visitedStops = {2, 3, 4, 5, 6, 7, 9, 10}
- Not the target, mark visited and enqueue:
- Stop 8:
- Not the target, mark visited and enqueue:
queue = [(9, 2), (10, 2), (6, 3), (7, 3), (8, 3)],visitedStops = {2, 3, 4, 5, 6, 7, 8, 9, 10}
- Not the target, mark visited and enqueue:
- Stops visited by bus 1:
- Bus 2:
- Already used, skip.
- Bus 1:
- Buses visiting stop 5:
- Dequeue (9, 2):
current_stop = 9,buses_taken = 2- Buses visiting stop 9:
[2](already used, skip)
- Buses visiting stop 9:
- Dequeue (10, 2):
current_stop = 10,buses_taken = 2- Buses visiting stop 10:
[2, 3]- Bus 2:
- Already used, skip.
- Bus 3:
- Stops visited by bus 3:
[10, 12] - Stop 10:
- Already visited, skip.
- Stop 12:
- Target reached, return
buses_taken + 1 = 3.
- Target reached, return
- Stops visited by bus 3:
- Bus 2:
- Buses visiting stop 10:
- Dequeue (3, 0):
-
Result:
- The minimum number of buses needed is
3.
- The minimum number of buses needed is
Code
import java.util.*;
public class Solution {
// Method to find the minimum number of buses required to travel from source to target
public int numBusesToDestination(int[][] routes, int source, int target) {
if (source == target) return 0; // If source and target are the same, no bus is needed
// Map bus stops to buses that visit them
Map<Integer, List<Integer>> stopToBuses = new HashMap<>();
for (int i = 0; i < routes.length; i++) {
for (int stop : routes[i]) {
stopToBuses.computeIfAbsent(stop, k -> new ArrayList<>()).add(i);
// Create a mapping from each stop to the list of buses that visit that stop
}
}
// BFS setup
Queue<int[]> queue = new LinkedList<>();
Set<Integer> visitedStops = new HashSet<>();
Set<Integer> usedBuses = new HashSet<>();
queue.offer(new int[] { source, 0 }); // Start BFS with the source stop and 0 buses taken
visitedStops.add(source); // Mark the source stop as visited
while (!queue.isEmpty()) {
int[] current = queue.poll(); // Dequeue the current stop and buses taken
int stop = current[0];
int buses = current[1];
for (int bus : stopToBuses.get(stop)) {
if (usedBuses.contains(bus)) continue; // Skip buses that have already been used
usedBuses.add(bus); // Mark the current bus as used
for (int nextStop : routes[bus]) {
if (nextStop == target) return buses + 1; // Found the target stop
if (visitedStops.add(nextStop)) {
queue.offer(new int[] { nextStop, buses + 1 }); // Enqueue the next stop with one more bus taken
}
}
}
}
return -1; // If target is not reachable, return -1
}
// Main method to test the solution with provided examples
public static void main(String[] args) {
Solution solution = new Solution();
// Example 1
int[][] routesA = {
{ 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 4, 5, 9, 10 },
{ 10, 12 },
};
System.out.println(solution.numBusesToDestination(routesA, 3, 12)); // Output: 3
// Example 2
int[][] routesB = { { 1, 2, 3, 4, 5 }, { 5, 6, 7, 8 }, { 8, 9, 10, 11 } };
System.out.println(solution.numBusesToDestination(routesB, 1, 11)); // Output: 3
// Example 3
int[][] routesC = { { 1, 2, 5 }, { 3, 6, 7 }, { 7, 9, 10 } };
System.out.println(solution.numBusesToDestination(routesC, 2, 10)); // Output: -1
}
}
Complexity Analysis
Time Complexity
- Constructing the
stopToBusesmap requires iterating over each route and each stop within the route, which takestime, where (M) is the number of routes and (K) is the average number of stops per route. - During the BFS, each bus route and each stop will be processed. For each route in the queue, we iterate over its stops, and for each stop, we iterate over the connected routes in the map
stopToBuses. This takestime, resulting in a total time complexity of .
Space Complexity
- The
stopToBusesmap requiresspace to store all bus stops and their corresponding routes. - The BFS queue can store up to
elements in the worst case. - The
visitedStopsandusedBusessets will store up toelements. - Thus, the total space complexity is
.
🤖 Don't fully get this? Learn it with Claude
Stuck on Bus Routes? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Bus Routes** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Bus Routes** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Bus Routes**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Bus Routes**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.