LeetCode 记录-1697. 检查边长度限制的路径是否存在
我的解法
思路
可以看到,对于 queries 中的每一个查询项,其中,我们可以使用将无向图边集中互通且满足长度小于节点放在一个集合,当查询的两个节点,处在同一个集合的时候,表明查询有效,返回 true,否则返回 false。
这个思路可以使用并查集来实现。
什么是并查集?
并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。
顾名思义,并查集支持两种操作:
- 合并(Union): 合并两个元素所属集合(合并对应的树)。
- 查询(Find): 查询某个元素所属集合(查询对应的树的根节点),还可以用于判断两个元素是否属于同一集合。
官方解法 1: 离线查询 + 并查集
思路
官方也是采用了并查集的方法,但同时还采用了离线查询,只要建立一个并查集就可以查询出所有的结果。 我们可以通过官方的思路看到:
- 如果的是非递减的,显然上一次查询的并查集里的边都是满足当前查询的需求的,我们只需要将剩余的长度小于的边加入并查集中即可。所以首先将按从小到大进行排序。
- 同时,将按边长度从小到大进行排序,使用指向上一次查询中不满足要求的长度的最小的边,初始时。
在满足以上要求后,我们就可以遍历一遍和来实现查询所有的结果。
代码
/**
* @param {number} n
* @param {number[][]} edgeList
* @param {number[][]} queries
* @return {boolean[]}
*/
var distanceLimitedPathsExist = function (n, edgeList, queries) {
edgeList.sort((a, b) => a[2] - b[2]);
const index = new Array(queries.length).fill(0);
for (let i = 0; i < queries.length; i++) {
index[i] = i;
}
index.sort((a, b) => queries[a][2] - queries[b][2]);
const uf = new Array(n).fill(0);
for (let i = 0; i < n; i++) {
uf[i] = i;
}
const ans = new Array(queries.length).fill(0);
let k = 0;
for (let i of index) {
while (k < edgeList.length && edgeList[k][2] < queries[i][2]) {
merge(uf, edgeList[k][0], edgeList[k][1]);
k++;
}
ans[i] = find(uf, queries[i][0]) === find(uf, queries[i][1]);
}
return ans;
};
const find = (uf, x) => {
if (uf[x] === x) {
return x;
}
return (uf[x] = find(uf, uf[x]));
};
const merge = (uf, x, y) => {
x = find(uf, x);
y = find(uf, y);
uf[y] = x;
};
复杂度分析
时间复杂度
,其中是的长度,是的长度,是点数。对和进行排序分别需要和,并查集初始化需要,并查集查询和合并总共需要。
空间复杂度
,保存并查集需要的空间,保存需要的空间,以及排序需要的栈空间。