开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第25天,点击查看活动详情
给你一个 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 。
示例 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:
输入: n = 5, edgeList = [[0,1,10],[1,2,5],[2,3,9],[3,4,13]], queries = [[0,4,14],[1,4,13]]
输出: [true,false]
解释: 上图为给定数据。
提示:
2 <= n <= 10^51 <= edgeList.length, queries.length <= 10^5edgeList[i].length == 3queries[j].length == 30 <= ui, vi, pj, qj <= n - 1ui != vipj != qj1 <= disi, limitj <= 10^9- 两个点之间可能有 多条 边。
思路
看到本题,第一反应就是深度优先遍历。用一个n * n的二维数组来保存点之间边的长度,如果存在多条边,取长度最小的值。判断两点是否连通且路径上每条边的长度都小于limit,可以从起始点进行深度遍历,遍历条件是两点间存在边且边长小于limit,如果通过遍历可以到得结束点,返回true,否则返回false,如解法一。
深度优先遍历虽然可以求解,但是超出了题目的时间限制。判断连通性,还可以使用归并集求解。归并集的定义及操作我们以后再说,简单的理解就是初始化时,我们把n个点划分为n个集合,当两点间存在长度小于limit的边时,我们把这两个点所在的集合并为一个集合。最后起始点和结束点在一个集合里说明两点间连通且路径边长都小于limit,返回true,否则返回false。求多组点连通性,我们可以按照限制值升序排序,同时我们也把所有的边按照边长升序排序,这样可以减少遍历次数,更快的求解,如解法二。
解题
解法一
/**
* @param {number} n
* @param {number[][]} edgeList
* @param {number[][]} queries
* @return {boolean[]}
*/
var distanceLimitedPathsExist = function (n, edgeList, queries) {
const graph = new Array(n)
.fill(null)
.map((_) => new Array(n).fill(Number.MAX_SAFE_INTEGER));
for (let i = 0; i < edgeList.length; i++) {
const [x, y, value] = edgeList[i];
if (value < graph[x][y]) {
graph[x][y] = value;
graph[y][x] = value;
}
}
const dfs = (start, end, max, arr) => {
if (start === end) return true;
arr[start] = true;
for (let i = 0; i < n; i++) {
if (!arr[i] && graph[start][i] < max) {
if (dfs(i, end, max, arr)) {
return true;
}
}
}
return false;
};
let res = new Array(queries.length).fill(false);
let arr = new Array(n).fill(false);
for (let i = 0; i < queries.length; i++) {
arr.fill(false);
res[i] = dfs(...queries[i], arr);
}
return res;
};
解法二
/**
* @param {number} n
* @param {number[][]} edgeList
* @param {number[][]} queries
* @return {boolean[]}
*/
var distanceLimitedPathsExist = function (n, edgeList, queries) {
const uf = new Array(n).fill(null).map((_, i) => i);
const find = (uf, x) => {
if (uf[x] !== x) {
uf[x] = find(uf, uf[x]);
}
return uf[x];
};
const merge = (uf, x, y) => {
x = find(uf, x);
y = find(uf, y);
uf[y] = x;
};
const m = edgeList.length;
const len = queries.length;
for (let i = 0; i < len; i++) {
queries[i][3] = i;
}
queries.sort((a, b) => a[2] - b[2]);
edgeList.sort((a, b) => a[2] - b[2]);
let i = 0;
let j = 0;
const res = new Array(len).fill(false);
while (i < m && j < len) {
if (edgeList[i][2] >= queries[j][2]) {
res[queries[j][3]] = find(uf, queries[j][0]) === find(uf, queries[j][1]);
j++;
} else {
merge(uf, edgeList[i][0], edgeList[i][1]);
i++;
}
}
for (; j < len; j++) {
res[queries[j][3]] = find(uf, queries[j][0]) === find(uf, queries[j][1]);
}
return res;
};