算法小练习之检查边长度限制的路径是否存在

112 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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

image.png

输入: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

image.png

输入: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、执行结果

image.png

好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊