检查边长度限制的路径是否存在【LC1679】
给你一个
n个点组成的无向图边集edgeList,其中edgeList[i] = [ui, vi, disi]表示点ui和点vi之间有一条长度为disi的边。请注意,两个点之间可能有 超过一条边 。给你一个查询数组
queries,其中queries[j] = [pj, qj, limitj],你的任务是对于每个查询queries[j],判断是否存在从pj到qj的路径,且这条路径上的每一条边都 严格小于limitj。请你返回一个 布尔数组
answer,其中answer.length == queries.length,当queries[j]的查询结果为true时,answer第j个值为true,否则为false。
An undirected graph of
nnodes is defined byedgeList, whereedgeList[i] = [ui, vi, disi]denotes an edge between nodesuiandviwith distancedisi. Note that there may be multiple edges between two nodes.Given an array
queries, wherequeries[j] = [pj, qj, limitj], your task is to determine for eachqueries[j]whether there is a path betweenpjandqjsuch that each edge on the path has a distance strictly less thanlimitj.Return a boolean array
answer, whereanswer.length == queries.lengthand thejthvalue ofansweristrueif there is a path forqueries[j]istrue, andfalseotherwise.
同门阳了 我指希望不要太难受 这周把这类并查集搞定
BFS【超时】
-
思路:将输入的
edgeList转换成邻接表adList,维护一个小顶堆pq可以暴力计算出查询数组queries中各个起点到各个终点边长度最短的路径,从而判断是否存在办长度限制的路径pq中的元素为节点编号以及起点到该节点的路径长度,并以路径长度为比较元素。每次取出未访问过的节点中的路径最短的节点,并访问其邻接点,若路径长度仍小于等于queries[2]且未访问过,可将其放入pq,直至pq为空或 边大于queries[2]。
-
实现
class Solution { public boolean[] distanceLimitedPathsExist(int n, int[][] edgeList, int[][] queries) { boolean[] res = new boolean[queries.length]; // 构建邻接表 List<int[]>[] adList = new List[n]; for (int i = 0; i < n; i++){ adList[i] = new ArrayList<int[]>(); } for (int[] edge : edgeList){ int u = edge[0], v = edge[1], dis = edge[2]; adList[u].add(new int[]{v, dis}); adList[v].add(new int[]{u, dis}); } for (int i = 0; i < queries.length; i++){ int start = queries[i][0], end = queries[i][1], limit = queries[i][2]; PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> a[0] - b[0]); pq.offer(new int[]{0, start}); Set<Integer> visited = new HashSet<>(); // 寻找路径 while(!pq.isEmpty() && pq.peek()[0] < limit){ int[] poll = pq.poll(); int dis = poll[0], u = poll[1]; if (!visited.add(u)){ continue; } if (u == end){ res[i] = true; break; } // 加入下一个可以访问的节点 for (int[] next : adList[u]){ int v = next[0], disNext = next[1]; if (!visited.contains(v)){ pq.offer(new int[]{disNext, v}); } } } } return res; } }-
复杂度
- 时间复杂度:O(E×logV×m)O(E×logV×m)O(E×logV×m),VVV 为节点数,即 nnn,EEE为输入
edgeList的长度,mmm为queries的长度。邻接表 adList的时间复杂度为 O(E)O(E)O(E),搜索路径的时间复杂度为 O(E×logV)O(E×logV)O(E×logV)。 - 空间复杂度:O(V+E)O(V+E)O(V+E),邻接表
adList的空间复杂度为 O(E)O(E)O(E),pq的空间复杂度为 O(E)O(E)O(E),visited的空间复杂度为 O(V)O(V)O(V),总的空间复杂度为 O(V+E)O(V+E)O(V+E)。
- 时间复杂度:O(E×logV×m)O(E×logV×m)O(E×logV×m),VVV 为节点数,即 nnn,EEE为输入
-
并查集
-
离线查询:对于一道题目会给出若干询问,而这些询问是全部提前给出的,也就是说,你不必按照询问的顺序依次对它们进行处理,而是可以按照某种顺序(例如全序、偏序(拓扑序)、树的 DFS 序等)或者把所有询问看成一个整体(例如整体二分、莫队算法等)进行处理。
-
思路:
- 使用并查集维护图的连通性,对于
queries[i],我们可以将edgeList中所有长度小于limit的边加入到并查集中,然后使用并查集查询u和v是否属于同一个集合。如果u和v属于同一个集合,则说明存在从u到v的路径,且这条路径上的每一条边的长度都严格小于limit,查询返回true,否则查询返回false。 - 因此可以将
queries按照limit从小到大进行排序,并将edgeList按照距离dis从小到大进行排序,使用指针k定位上一次查询中不满足limit要求的长度最小的边,以便于使用离线查询的思维处理queries中的询问,降低时间复杂度
- 使用并查集维护图的连通性,对于
-
实现
- 排序
- 依次遍历
queries:如果k指向的边的长度小于对应查询的limit,则将该边加入并查集中,然后将k加 1,直到k指向的边不满足要求;最后根据并查集查询对应的u和v是否属于同一集合来保存查询的结果。
class Solution { private int[] father; public boolean[] distanceLimitedPathsExist(int n, int[][] edgeList, int[][] queries) { // 记录初始下标 Integer[] index = new Integer[queries.length]; for (int i = 0; i < queries.length; i++){ index[i] = i; } // 排序 Arrays.sort(edgeList, (a, b) -> a[2] - b[2]); Arrays.sort(index, (a, b) -> queries[a][2] - queries[b][2]); // 并查集初始化 father = new int[n]; for (int i = 0; i < n; i++){ father[i] = i; } boolean[] res = new boolean[queries.length]; int k = 0; for (int i : index){ while (k < edgeList.length && edgeList[k][2] < queries[i][2]){ join(edgeList[k][0],edgeList[k][1]); k++; } res[i] = find(queries[i][0]) == find(queries[i][1]); } return res; } private int find(int u){ if (u == father[u]){ return u; } father[u] = find(father[u]); return father[u]; } private void join (int u, int v){ u = find(u); v = find(v); if (u == v) return; father[v] = u; } }-
复杂度
- 时间复杂度:O(ElogE+mlogm+(E+m)logn+n)O(ElogE+mlogm+(E+m)log n + n)O(ElogE+mlogm+(E+m)logn+n),nnn 为节点数,EEE为输入
edgeList的长度,mmm为queries的长度。对edgeList和queries排序时间复杂度分别为 O(ElogE)O(ElogE)O(ElogE)和 O(mlogm)O(mlogm)O(mlogm),并查集初始化的时间复杂度为 O(n)O(n)O(n),并查集查询和合并的时间复杂度为 O((E+m)logn)O((E+m)logn)O((E+m)logn)。 - 空间复杂度:O(logE+m+n)O(logE+m+n)O(logE+m+n),保存并查集的空间复杂度为 O(n)O(n)O(n),保存下标的空间复杂度为 O(m)O(m)O(m),对
edgeList排序的空间复杂度为 O(logE)O(logE)O(logE),对queries排序的空间复杂度可以忽略
- 时间复杂度:O(ElogE+mlogm+(E+m)logn+n)O(ElogE+mlogm+(E+m)log n + n)O(ElogE+mlogm+(E+m)logn+n),nnn 为节点数,EEE为输入

本文探讨了在给定边长度限制条件下检查两点间是否存在有效路径的问题。介绍了两种解决方案:一种是使用BFS方法,但由于效率问题易超时;另一种是采用并查集算法离线处理查询,显著提高了效率。
2万+

被折叠的 条评论
为什么被折叠?



