1697. Checking Existence of Edge Length Limited Paths
Idea#
This problem at first looks a lot like a shortest path problem, but the test case size(\(10^5\)) seems to be too big.
Another observation is that the problem doesn’t really ask for shortest path, instead it asks if the max weight along the path is smaller than something, (hopefully) this relaxes the problem a little bit.
As there is no easy way to find out the max path weight given two random nodes in the graph(probably just DFS and BFS, which result in \(n^2\) time complexity, Floyd-Warshall algorithm has \(n^3\)), we try something else.
We have edge list with weight and queries with weight, and we want to find if two nodes are connected given a max path weight. Then how about we try to connect only edges that meet the weight requirement? If query[2]
is 10, we only “connect” the graph using edges that has weight less than 10, then the problem is simplified to:
at this moment, are the two nodes connected?
We have many ways to solve this, Union Find is the one I choose!
Steps#
Sort edge list by weight, and we start from the query with smallest weight requirement.
Manipulate the queries a bit, pair each query with its original index, and sort it by weight, so later we can put the answer to the correct position.
Loop through (the new) queries, and go through all the edges which have weight less than query[2]
, union the nodes, and find if the two nodes are connected, fill answer using the original index.
Algorithm#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
class Solution:
def distanceLimitedPathsExist(self, n: int, edgeList: List[List[int]], queries: List[List[int]]) -> List[bool]:
uf=UnionFind(n)
edgeList.sort(key=lambda x:x[2])
res=[False for _ in range(len(queries))]
# queries_pair
qp=[]
for i,query in enumerate(queries):
qp.append((query,i))
qp.sort(key=lambda x:x[0][2])
qp_pointer=0
el_pointer=0
while qp_pointer<len(qp):
query,idx=qp[qp_pointer]
# only union nodes that have edge weight strictly less than current query weight
# we can union in sequence bcuz edge list has been sorted by weight
while el_pointer<len(edgeList) and edgeList[el_pointer][2]<query[2]:
start,end,_ = edgeList[el_pointer]
uf.union(start,end)
el_pointer+=1
res[idx]=uf.find(query[0])==uf.find(query[1])
qp_pointer+=1
return res
# standard UF
class UnionFind:
def __init__(self,n):
self.roots=[i for i in range(n)]
self.ranks=[1 for _ in range(n)]
def find(self,x):
xr=self.roots[x]
if xr==x:
return xr
self.roots[x]=self.find(xr)
return self.roots[x]
def union(self,x,y):
xr=self.find(x)
yr=self.find(y)
if xr==yr:
return
if self.ranks[xr]>self.ranks[yr]:
self.roots[yr]=xr
elif self.ranks[xr]<self.ranks[yr]:
self.roots[xr]=yr
else:
self.roots[xr]=yr
self.ranks[yr]+=1
|
End#
Btw GPT-4’s solution uses Floyd-Warshall algorithm and results in TLE 🤣
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
def path_within_limits(n, edgeList, queries):
# Initialize a graph representation using adjacency matrix
graph = [[float('inf')] * n for _ in range(n)]
# Populate the graph with edge distances
for u, v, dis in edgeList:
graph[u][v] = min(graph[u][v], dis)
graph[v][u] = min(graph[v][u], dis)
# Apply the Floyd-Warshall algorithm
for k in range(n):
for i in range(n):
for j in range(n):
graph[i][j] = min(graph[i][j], max(graph[i][k], graph[k][j]))
# Answer the queries
result = []
for p, q, limit in queries:
result.append(graph[p][q] < limit)
return result
|