An undirected graph of n nodes is defined by edgeList, where edgeList[i] = [ui, vi, disi] denotes an edge between nodes ui and vi with distance disi. Note that there may be multiple edges between two nodes.
Given an array queries, where queries[j] = [pj, qj, limitj], your task is to determine for each queries[j] whether there is a path between pj and qj such that each edge on the path has a distance strictly less than limitj .
Return a boolean array answer, where answer.length == queries.length and the jth value of answer is true if there is a path for queries[j] is true, and false otherwise.
Example 1:
Input: n = 3, edgeList = [[0,1,2],[1,2,4],[2,0,8],[1,0,16]], queries = [[0,1,2],[0,2,5]] Output: [false,true] Explanation: The above figure shows the given graph. Note that there are two overlapping edges between 0 and 1 with distances 2 and 16. For the first query, between 0 and 1 there is no path where each distance is less than 2, thus we return false for this query. For the second query, there is a path (0 -> 1 -> 2) of two edges with distances less than 5, thus we return true for this query.
Example 2:
Input: n = 5, edgeList = [[0,1,10],[1,2,5],[2,3,9],[3,4,13]], queries = [[0,4,14],[1,4,13]] Output: [true,false] Explanation: The above figure shows the given graph.
Constraints:
2 <= n <= 1051 <= edgeList.length, queries.length <= 105edgeList[i].length == 3queries[j].length == 30 <= ui, vi, pj, qj <= n - 1ui != vipj != qj1 <= disi, limitj <= 109When 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 problem asks whether there is a path between two locations with all the roads on the path being shorter than some given limit. The brute force method simply tries every possible path between the locations to see if any of them satisfy the limit.
Here's how the algorithm would work step-by-step:
def check_existence_edge_length_limited_paths_brute_force(number_of_nodes, edge_list, queries): adjacency_list = [[] for _ in range(number_of_nodes)]
for node_a, node_b, edge_length in edge_list:
adjacency_list[node_a].append((node_b, edge_length))
adjacency_list[node_b].append((node_a, edge_length))
results = []
for start_node, end_node, length_limit in queries:
found_path = False
def depth_first_search(current_node, destination_node, current_path, max_edge_length):
nonlocal found_path
if current_node == destination_node:
found_path = True
return
for neighbor_node, edge_length in adjacency_list[current_node]:
if neighbor_node not in current_path:
# Only explore paths that satisfy the length limit condition
if edge_length < length_limit:
depth_first_search(neighbor_node, destination_node, current_path + [neighbor_node], max_edge_length)
# Initiate search
depth_first_search(start_node, end_node, [start_node], length_limit)
# Determine if a path exists
results.append(found_path)
return resultsThe problem asks us to determine if paths exist between node pairs with edge lengths less than a given limit. We can efficiently solve this using a combination of sorting edges and path limits, and a data structure that helps us track connected components.
Here's how the algorithm would work step-by-step:
def checking_existence_of_edge_length_limited_paths(
number_of_nodes,
edge_list,
queries):
parent = list(range(number_of_nodes))
def find(node):
if parent[node] != node:
parent[node] = find(parent[node])
return parent[node]
def union(node1, node2):
root1 = find(node1)
root2 = find(node2)
if root1 != root2:
parent[root1] = root2
# Store the index of each query to restore the original order
indexed_queries = [(edge_max, node1, node2, index)
for index, (node1, node2, edge_max) in enumerate(queries)]
indexed_queries.sort()
edge_list.sort(key=lambda x: x[2])
results = [False] * len(queries)
edge_index = 0
# Iterate through the queries in sorted order
for edge_max, node1, node2, index in indexed_queries:
# Add edges to the union-find structure until
# the current edge exceeds the query limit.
while edge_index < len(edge_list) and \
edge_list[edge_index][2] < edge_max:
union(edge_list[edge_index][0], edge_list[edge_index][1])
edge_index += 1
# Check connectivity only after adding all
# relevant edges for the current query
results[index] = find(node1) == find(node2)
return results| Case | How to Handle |
|---|---|
| Empty edge list or queries list | Return an empty result array/list immediately as there are no paths or queries to process. |
| Graph with a single node | If the graph has only one node, all queries should return false since no edges exist. |
| Edges list with duplicate edges | The algorithm should correctly process duplicate edges, effectively keeping only one instance of each edge. |
| Queries with identical edge limits | The sorting of queries with identical limits must be stable, preserving the original order to meet output requirements. |
| Edge limits with very large values (potential integer overflow during calculations) | Ensure intermediate calculations related to edge lengths do not overflow integer limits, potentially using long data types. |
| Graph with cycles | The solution should function correctly with cycles, likely needing a Disjoint Set Union (DSU) approach to avoid infinite loops. |
| Maximum number of nodes and edges (scalability) | Verify that the DSU operations and sorting algorithms used perform within the time limit for the maximum input size. |
| Disjoint graph (no path between some nodes) | Queries between disjoint components should return false as no path satisfying the limit exists. |