Find optimal commute mode in a city graph
Company: Databricks
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of graph traversal and shortest-path concepts, particularly handling multiple mode-restricted subgraphs and multi-criteria comparison of path metrics (time and cost) across modes.
Part 1: Compute commute metrics for every mode
Constraints
- 1 <= N <= 100000
- 0 <= len(roads) <= 200000
- 1 <= K <= 10
- 0 <= S, D < N
- Each road is undirected
- Each allowed_modes list is non-empty and contains mode IDs in 0..K-1
- time_per_edge[m] and cost_per_edge[m] are non-negative integers
Examples
Input: (5, [(0, 1, [0, 1]), (1, 2, [0]), (2, 4, [0, 1]), (0, 3, [1]), (3, 4, [1])], 2, 0, 4, [5, 3], [2, 4])
Expected Output: [(3, 15, 6), (2, 6, 8)]
Explanation: Mode 0 uses path 0-1-2-4 with 3 edges. Mode 1 uses path 0-3-4 with 2 edges.
Input: (3, [(0, 1, [0]), (1, 2, [1])], 2, 1, 1, [7, 2], [5, 1])
Expected Output: [(0, 0, 0), (0, 0, 0)]
Explanation: Start equals destination, so every mode reaches D with 0 edges.
Input: (4, [(0, 1, [0, 1]), (1, 2, [0]), (2, 3, [0])], 2, 0, 3, [2, 10], [1, 1])
Expected Output: [(3, 6, 3), (-1, -1, -1)]
Explanation: Mode 0 reaches 3 in 3 edges. Mode 1 can only travel from 0 to 1, so 3 is unreachable.
Input: (2, [], 3, 0, 1, [1, 2, 3], [4, 5, 6])
Expected Output: [(-1, -1, -1), (-1, -1, -1), (-1, -1, -1)]
Explanation: With no roads and different start/destination nodes, no mode can reach the destination.
Solution
def solution(N, roads, K, S, D, time_per_edge, cost_per_edge):
from collections import deque
adj = [[] for _ in range(N)]
for u, v, allowed_modes in roads:
mask = 0
for m in allowed_modes:
mask |= 1 << m
adj[u].append((v, mask))
adj[v].append((u, mask))
results = []
for m in range(K):
bit = 1 << m
dist = [-1] * N
q = deque([S])
dist[S] = 0
while q:
node = q.popleft()
if node == D:
break
for nei, mask in adj[node]:
if dist[nei] == -1 and (mask & bit):
dist[nei] = dist[node] + 1
q.append(nei)
if dist[D] == -1:
results.append((-1, -1, -1))
else:
edges = dist[D]
results.append((edges, edges * time_per_edge[m], edges * cost_per_edge[m]))
return results
Time complexity: O(A + K * (N + M)), where A is the total number of mode IDs listed across all roads and M is the number of roads. Space complexity: O(N + M).
Hints
- For one fixed mode, every usable road has equal weight in terms of edge count, so BFS gives the minimum number of edges.
- You do not need Dijkstra here. Build the graph once, then run a separate BFS for each mode.
Part 2: Choose the optimal commute mode
Constraints
- 1 <= len(mode_metrics) <= 100000
- Each entry is a tuple (time, cost)
- A valid mode has time >= 0 and cost >= 0
- An invalid mode is represented by (-1, -1)
Examples
Input: ([(15, 6), (6, 8), (10, 2)],)
Expected Output: (1, (6, 8))
Explanation: Mode 1 has the smallest total time.
Input: ([(-1, -1), (5, 10), (5, 7), (7, 1)],)
Expected Output: (2, (5, 7))
Explanation: Modes 1 and 2 tie on time, so the cheaper one, mode 2, is chosen.
Input: ([(-1, -1), (-1, -1)],)
Expected Output: (-1, (-1, -1))
Explanation: All modes are invalid.
Input: ([(4, 3), (4, 3), (6, 1)],)
Expected Output: (0, (4, 3))
Explanation: Modes 0 and 1 are equally optimal. Returning the first one is acceptable.
Input: ([(0, 0)],)
Expected Output: (0, (0, 0))
Explanation: Single-mode boundary case.
Solution
def solution(mode_metrics):
best_mode = -1
best_time = -1
best_cost = -1
for mode, (time, cost) in enumerate(mode_metrics):
if time < 0 or cost < 0:
continue
if best_mode == -1 or time < best_time or (time == best_time and cost < best_cost):
best_mode = mode
best_time = time
best_cost = cost
if best_mode == -1:
return (-1, (-1, -1))
return (best_mode, (best_time, best_cost))
Time complexity: O(K). Space complexity: O(1).
Hints
- You only need a single pass through the list while keeping track of the current best mode.
- Update the best answer if you find a smaller time, or the same time with a smaller cost.