持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情
1、前言
每天一个算法小练习,本篇使用Java实现。
2、题目描述
给你一个 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 。
2.1、示例1
输入:n = 3, edgeList = [[0,1,2],[1,2,4],[2,0,8],[1,0,16]], queries = [[0,1,2],[0,2,5]]
输出:[false,true]
解释:上图为给定的输入数据。注意到 0 和 1 之间有两条重边,分别为 2 和 16 。
对于第一个查询,0 和 1 之间没有小于 2 的边,所以我们返回 false 。
对于第二个查询,有一条路径(0 -> 1 -> 2)两条边都小于 5 ,所以这个查询我们返回 true 。
2.2、示例2
输入:n = 5, edgeList = [[0,1,10],[1,2,5],[2,3,9],[3,4,13]], queries = [[0,4,14],[1,4,13]]
输出:[true,false]
解释:上图为给定数据。
3、解题思路
结合并查集实现,这道题本质上是带条件的连通性考量问题。我们先将 edgeList 按照边值从小到大排序,再将 queries 按照 limit 从小到大排序,这样对于每个 query 都可以加入小于等于 limit 的边,然后去判断这个 query 对应的两个顶点是否连通。
3.1、实现代码
class Union {
//并查集模板
int[] parent;
int[] size;
public Union(int n) {
this.parent = new int[n];
this.size = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}
public void union(int x, int y) {
int rootX = findP(x);
int rootY = findP(y);
if (rootX != rootY) {
//连接
if (size[rootX] > size[rootY]) {
size[rootX] += size[rootY];
parent[rootY] = rootX;
} else {
size[rootY] += size[rootX];
parent[rootX] = rootY;
}
}
}
public int findP(int x){
//找到 x 的父亲节点
while(x != parent[x]){
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public boolean connect(int x, int y) {
// 判断 x 和 y 是否连通
return findP(x) == findP(y);
}
}
/**
* 边长排序,将小于查询边长的节点全部连接,然后只需要判断要查询的节点连不连通即可
* @param n
* @param edgeList
* @param queries
* @return
*/
public boolean[] distanceLimitedPathsExist(int n, int[][] edgeList, int[][] queries) {
Union union = new Union(n);
//排序
Arrays.sort(edgeList, Comparator.comparingInt(a -> a[2]));
int size = queries.length;
boolean[] res = new boolean[size];
int i = 0;
Map<int[], Integer> map = new HashMap<>();
for (int[] query : queries) {
map.put(query, i++);
}
//排序
Arrays.sort(queries, Comparator.comparingInt(a -> a[2]));
int index = 0;
for (int[] arr : queries) {
while (index < edgeList.length && edgeList[index][2] < arr[2]) {
//将小于等于 limit 边的 edge 加入现在的图中
union.union(edgeList[index][0], edgeList[index][1]);
++index;
}
//判断两个顶点的连通性作为结果
res[map.get(arr)] = union.connect(arr[0], arr[1]);
}
return res;
}
3.2、执行结果
好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊