【1697. 检查边长度限制的路径是否存在】

来源:力扣(LeetCode)

描述:

给你一个 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:

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]
解释:上图为给定的输入数据。注意到 01 之间有两条重边,分别为 216 。
对于第一个查询,01 之间没有小于 2 的边,所以我们返回 false 。
对于第二个查询,有一条路径(0 -> 1 -> 2)两条边都小于 5 ,所以这个查询我们返回 true

示例 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]
解释:上图为给定数据。

提示:

  • 2 <= n <= 105
  • 1 <= edgeList.length, queries.length <= 105
  • edgeList[i].length == 3
  • queries[j].length == 3
  • 0 <= ui, vi, pj, qj <= n - 1
  • ui != vi
  • pj != qj
  • 1 <= disi, limitj <= 109
  • 两个点之间可能有 多条 边。

前言

  关于并查集的详细说明可以参考 OI Wiki「并查集」或者 LeetBook「并查集」,本文不作过多说明。

方法:离线查询 + 并查集

  给定一个查询时,我们可以遍历 edgeList 中的所有边,依次将长度小于 limit 的边加入到并查集中,然后使用并查集查询 p 和 q 是否属于同一个集合。如果 p 和 q 属于同一个集合,则说明存在从 p 到 q 的路径,且这条路径上的每一条边的长度都严格小于 limit,查询返回 true,否则查询返回 false。

  如果 queries 的 limit 是非递减的,显然上一次查询的并查集里的边都是满足当前查询的 limit 要求的,我们只需要将剩余的长度小于 limit 的边加入并查集中即可。基于此,我们首先将 edgeList 按边长度从小到大进行排序,然后将 queries 按 limit 从小到大进行排序,使用 k 指向上一次查询中不满足 limit 要求的长度最小的边,显然初始时 k = 0。

  我们依次遍历 queries:如果 k 指向的边的长度小于对应查询的 limit,则将该边加入并查集中,然后将 k 加 1,直到 k 指向的边不满足要求;最后根据并查集查询对应的 p 和 q 是否属于同一集合来保存查询的结果。

代码:

class Solution {
public:
    int find(vector<int> &uf, int x) {
        if (uf[x] == x) {
            return x;
        }
        return uf[x] = find(uf, uf[x]);
    }

    void merge(vector<int> &uf, int x, int y) {
        x = find(uf, x);
        y = find(uf, y);
        uf[y] = x;
    }

    vector<bool> distanceLimitedPathsExist(int n, vector<vector<int>>& edgeList, vector<vector<int>>& queries) {
        sort(edgeList.begin(), edgeList.end(), [](vector<int> &e1, vector<int> &e2) {
            return e1[2] < e2[2];
        });

        vector<int> index(queries.size());
        iota(index.begin(), index.end(), 0);
        sort(index.begin(), index.end(), [&](int i1, int i2) {
            return queries[i1][2] < queries[i2][2];
        });

        vector<int> uf(n);
        iota(uf.begin(), uf.end(), 0);
        vector<bool> res(queries.size());
        int k = 0;
        for (auto i : index) {
            while (k < edgeList.size() && edgeList[k][2] < queries[i][2]) {
                merge(uf, edgeList[k][0], edgeList[k][1]);
                k++;
            }
            res[i] = find(uf, queries[i][0]) == find(uf, queries[i][1]);
        }
        return res;
    }
};

执行用时:440 ms, 在所有 C++ 提交中击败了96.64%的用户
内存消耗:107.6 MB, 在所有 C++ 提交中击败了80.54%的用户
复杂度分析
时间复杂度:O(ElogE+mlogm+(E+m)logn+n),其中 E 是 edgeList 的长度,m 是 queriesqueries 的长度,n 是点数。对 edgeList 和 queries 进行排序分别需要 O(ElogE) 和 O(mlogm),并查集初始化需要 O(n),并查集查询和合并总共需要 O((E+m)logn)。
空间复杂度:O(logE+m+n)。保存并查集需要 O(n) 的空间,保存 index 需要 O(m) 的空间,以及排序需要的栈空间。
author:LeetCode-Solution

当我们在计算机上运行一个程序时,有时会遇到错误提示信息,例如"depcheck 文件路径不存在"。这个提示信息意味着程序无法找到指定的文件路径。 首先,我们需要了解这个错误的原因。一种可能性是我们在运行程序时,指定的文件路径不正确。我们需要检查一下我们输入的路径是否正确,包括文件名是否正确以及路径中是否有错误的分隔符或者多余的空格。如果文件路径是从其他地方复制过来的,我们也要确认复制的路径是否包含了特殊字符或者不可见的字符。 另外,这个错误提示还可能是因为我们指定的文件路径在计算机中根本不存在。这可能是因为文件在其他地方被移动或者删除了。我们可以通过在计算机上搜索文件名或者一些相关的关键词来查找文件。如果找不到文件,那就意味着它可能已经被永久删除了,这种情况下我们需要从备份或者其他来源找到具有相同功能的文件。 此外,这个错误还可能是因为文件路径太长或者包含了不允许的字符。在有些操作系统中,文件路径长度是有限制的,并且可能不允许使用一些特殊字符。我们可以尝试缩短文件路径或者更改文件名,以避免这个错误。 总之,当我们遇到"depcheck 文件路径不存在"这个错误时,我们需要仔细检查我们输入的文件路径是否正确,并尝试查找文件或者更改文件路径以解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千北@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值