You are given an integer n and a 2D integer array queries.
There are n cities numbered from 0 to n - 1. Initially, there is a unidirectional road from city i to city i + 1 for all 0 <= i < n - 1.
queries[i] = [ui, vi] represents the addition of a new unidirectional road from city ui to city vi. After each query, you need to find the length of the shortest path from city 0 to city n - 1.
Return an array answer where for each i in the range [0, queries.length - 1], answer[i] is the length of the shortest path from city 0 to city n - 1 after processing the first i + 1 queries.
Example 1:
Input: n = 5, queries = [[2,4],[0,2],[0,4]]
Output: [3,2,1]
Explanation:

After the addition of the road from 2 to 4, the length of the shortest path from 0 to 4 is 3.

After the addition of the road from 0 to 2, the length of the shortest path from 0 to 4 is 2.

After the addition of the road from 0 to 4, the length of the shortest path from 0 to 4 is 1.
Example 2:
Input: n = 4, queries = [[0,3],[0,2]]
Output: [1,1]
Explanation:

After the addition of the road from 0 to 3, the length of the shortest path from 0 to 3 is 1.

After the addition of the road from 0 to 2, the length of the shortest path remains 1.
Constraints:
3 <= n <= 5001 <= queries.length <= 500queries[i].length == 20 <= queries[i][0] < queries[i][1] < n1 < queries[i][1] - queries[i][0]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:
Imagine you have a map with cities and roads, and you want to find the shortest way to get from one city to another. We start with some roads, then add more roads one at a time. The brute force approach is like re-calculating the shortest path from start to end after each new road is added.
Here's how the algorithm would work step-by-step:
import heapq
def shortest_distance_after_road_additions_i(
number_of_nodes, edges, queries, source_node, destination_node
):
results = []
current_edges = edges[:] # Start with the initial edges
for query in queries:
current_edges.append(query)
# Calculate shortest path after adding the road
distance = dijkstra(
number_of_nodes, current_edges, source_node, destination_node
)
results.append(distance if distance != float('inf') else -1)
return results
def dijkstra(number_of_nodes, edges, source_node, destination_node):
graph = {i: [] for i in range(number_of_nodes)}
for source, destination, weight in edges:
graph[source].append((destination, weight))
distances = {i: float('inf') for i in range(number_of_nodes)}
distances[source_node] = 0
priority_queue = [(0, source_node)] # (distance, node)
while priority_queue:
current_distance, current_node = heapq.heappop(priority_queue)
if current_distance > distances[current_node]:
continue
for neighbor, weight in graph[current_node]:
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances[destination_node]We want to find the shortest paths between all pairs of locations as we add new roads. A clever approach involves updating shortest path distances only when a new road might create a shorter route between two locations, rather than recalculating everything from scratch each time.
Here's how the algorithm would work step-by-step:
def shortest_distance_after_road_addition(number_of_locations, edges, queries):
distance_matrix = [[float('inf')] * number_of_locations for _ in range(number_of_locations)]
for i in range(number_of_locations):
distance_matrix[i][i] = 0
for source, destination, weight in edges:
distance_matrix[source][destination] = weight
distance_matrix[destination][source] = weight
# Initialize shortest paths using Floyd-Warshall
for intermediate in range(number_of_locations):
for source in range(number_of_locations):
for destination in range(number_of_locations):
distance_matrix[source][destination] = min(
distance_matrix[source][destination],
distance_matrix[source][intermediate] + distance_matrix[intermediate][destination]
)
results = []
for source, destination, weight in queries:
# Adding a new road, check for possible shortest paths
for start_node in range(number_of_locations):
for end_node in range(number_of_locations):
# Checking if new road provides a shorter path
distance_matrix[start_node][end_node] = min(
distance_matrix[start_node][end_node],
distance_matrix[start_node][source] + weight + distance_matrix[destination][end_node],
distance_matrix[start_node][destination] + weight + distance_matrix[source][end_node]
)
shortest_distance = [[float('inf')] * number_of_locations for _ in range(number_of_locations)]
for i in range(number_of_locations):
shortest_distance[i][i] = 0
for start_node in range(number_of_locations):
for end_node in range(number_of_locations):
shortest_distance[start_node][end_node] = distance_matrix[start_node][end_node]
results.append(shortest_distance)
return results| Case | How to Handle |
|---|---|
| Null or empty road network (n=0 or queries is null/empty) | Return an empty list immediately, as there are no distances to calculate. |
| Single node graph (n=1) with queries | Return a list of all -1s because there are no other nodes to calculate the shortest distance to. |
| Queries that add edges creating a disconnected graph | Shortest path calculation should return -1 for nodes in separate components. |
| Queries add edges creating cycles in the graph. | The shortest path algorithm (e.g., Floyd-Warshall) should correctly handle cycles without infinite loops. |
| Maximum number of nodes and edges allowed by the problem constraints (potential memory issues). | Ensure that the adjacency matrix or other data structures used to represent the graph do not exceed available memory. |
| Integer overflow in distance calculations (especially with many edges). | Use a data type that can accommodate large distances (e.g., long) and check for overflow during calculations. |
| Queries that add duplicate edges. | Adding a duplicate edge should not change the shortest path; the algorithm handles it by updating the distance only if the new edge reduces it. |
| No path exists between certain node pairs even after all roads added. | The shortest path algorithm should return -1 for these node pairs. |