An undirected graph of n
nodes is defined by the integer n
. You are given a 2D integer array edges
where each edges[i] = [ui, vi, wi]
indicates that there is an undirected edge between nodes ui
and vi
with weight wi
.
You are also given a 2D integer array queries
where each queries[j] = [pj, qj, limitj]
asks if there is a path between nodes pj
and qj
such that each edge on the path has a weight strictly less than limitj
.
Return a boolean array answer
where answer[j]
is true
if there is a path between pj
and qj
such that each edge on the path has a weight strictly less than limitj
, and false
otherwise.
Since it is possible that multiple edges connect two nodes, you may assume that each edge has a unique weight.
Note:
edges[i].length == 3
0 <= ui, vi < n
ui != vi
1 <= wi <= 109
1 <= queries.length <= 105
queries[j].length == 3
0 <= pj, qj < n
pj != qj
1 <= limitj <= 109
Example 1:
Input: n = 3, edges = [[0,1,2],[1,2,4],[2,0,8],[1,0,16]], queries = [[0,1,2],[0,2,5]] Output: [false,true] Explanation: The first query asks if a path exists between 0 and 1 with all edges strictly less than 2. While the edge 0->1 has a weight less than 2, there are no paths between 0 and 1 where all edges are strictly less than 2. Therefore, the first query is false. The second query asks if a path exists between 0 and 2 with all edges strictly less than 5. The path 0->1->2 has edges with weights 2 and 4, which are both strictly less than 5. Therefore, the second query is true.
Example 2:
Input: n = 5, edges = [[0,1,10],[1,2,5],[2,3,9],[3,4,13]], queries = [[0,4,14],[1,4,13]] Output: [true,false] Explanation: The first query asks if a path exists between 0 and 4 with all edges strictly less than 14. The path 0->1->2->3->4 has edges with weights 10, 5, 9, and 13, which are all strictly less than 14. Therefore, the first query is true. The second query asks if a path exists between 1 and 4 with all edges strictly less than 13. The path 1->2->3->4 has edges with weights 5, 9, and 13, which are not all strictly less than 13. Therefore, the second query is false.
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:
The goal is to find a path between two locations where every road on that path has a length less than a given limit. The brute force method involves trying absolutely every possible route between the two locations and checking if it meets the length requirement.
Here's how the algorithm would work step-by-step:
def check_existence_edge_length_limited_paths_ii_brute_force(number_of_nodes, edge_list, queries):
answer = []
for start_node, end_node, length_limit in queries:
found_path = False
# Iterate through all possible paths to find a valid one
def depth_first_search(current_node, visited, current_path_length):
nonlocal found_path
if current_node == end_node:
found_path = True
return
visited[current_node] = True
# Explore all the adjacent nodes of current node
for neighbor_one, neighbor_two, edge_weight in edge_list:
if neighbor_one == current_node:
neighbor = neighbor_two
elif neighbor_two == current_node:
neighbor = neighbor_one
else:
continue
if not visited[neighbor] and edge_weight < length_limit:
# Recursive step
depth_first_search(neighbor, visited.copy(), current_path_length + edge_weight)
visited = [False] * number_of_nodes
depth_first_search(start_node, visited, 0)
answer.append(found_path)
return answer
This problem is about finding if you can travel between cities with roads that have certain length limits. The most efficient way to solve this involves pre-processing the road information and then efficiently checking if a path exists for each travel request, rather than re-calculating paths every time.
Here's how the algorithm would work step-by-step:
class Solution:
def distanceLimitedPathsExist(
self, number_of_nodes: int, edge_list: list[list[int]], queries: list[list[int]]
) -> list[bool]:
parent_nodes = list(range(number_of_nodes))
def find(node_index: int) -> int:
if parent_nodes[node_index] != node_index:
parent_nodes[node_index] = find(parent_nodes[node_index])
return parent_nodes[node_index]
def union(node_index_1: int, node_index_2: int):
root_1 = find(node_index_1)
root_2 = find(node_index_2)
if root_1 != root_2:
parent_nodes[root_1] = root_2
# Add query index to keep track of original order
indexed_queries = [query + [index] for index, query in enumerate(queries)]
indexed_queries.sort(key=lambda x: x[2])
edge_list.sort(key=lambda x: x[2])
results = [False] * len(queries)
edge_index = 0
# Iterate through queries in increasing order of limit
for start_node, end_node, length_limit, query_index in indexed_queries:
# Add edges smaller than current query limit
while edge_index < len(edge_list) and edge_list[edge_index][2] < length_limit:
node_1, node_2, _ = edge_list[edge_index]
union(node_1, node_2)
edge_index += 1
# Check if path exists between start and end node
results[query_index] = find(start_node) == find(end_node)
return results
Case | How to Handle |
---|---|
Null or empty graph (n=0) and empty edge list/queries | Return an empty boolean array immediately if the graph has no nodes and there are no edges or queries. |
Graph with one node (n=1) and non-empty edge list/queries | If there's one node, a path exists only if the source and destination are the same node, and the query length is non-negative. |
All edge lengths are the same, but shorter than some query lengths | The algorithm should correctly identify paths not exceeding the query length, even with uniform edge weights. |
Edge list contains duplicate edges (same u, v) with different lengths | The solution should pick the shortest edge between any two nodes if duplicates are provided, otherwise the longest edge could disconnect the components. |
Very large graph (n close to limit) with many queries (q close to limit) | Kruskal's algorithm with DSU needs to be implemented efficiently to avoid exceeding time and space constraints given a large number of nodes and queries. |
Edge weights are large integers nearing the maximum integer value | Ensure calculations (especially comparisons) do not lead to integer overflow; use 64-bit integers if needed. |
Queries with source and destination nodes being the same. | A path always exists between the same node, so return true if query length is non-negative and false otherwise. |
Graph is disconnected and queries ask about nodes in different components. | The algorithm should return false for such queries since no path exists between disconnected components regardless of edge length limits. |