侧边栏壁纸
博主头像
GabrielxD

列車は必ず次の駅へ。では舞台は?私たちは?

  • 累计撰写 471 篇文章
  • 累计创建 108 个标签
  • 累计收到 9 条评论

目 录CONTENT

文章目录

【图, 并查集】寻找图中是否存在路径

GabrielxD
2022-06-08 / 0 评论 / 0 点赞 / 27 阅读 / 618 字 / 正在检测是否收录...

题目

1971. 寻找图中是否存在路径


有一个具有 n个顶点的 双向 图,其中每个顶点标记从 0n - 1(包含 0n - 1)。图中的边用一个二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示顶点 ui 和顶点 vi 之间的双向边。 每个顶点对由 最多一条 边连接,并且没有顶点存在与自身相连的边。

请你确定是否存在从顶点 start 开始,到顶点 end 结束的 有效路径 。

给你数组 edges 和整数 nstartend,如果从 startend 存在 有效路径 ,则返回 true,否则返回 false

示例 1:

image-20220608192233858

输入:n = 3, edges = [[0,1],[1,2],[2,0]], start = 0, end = 2
输出:true
解释:存在由顶点 0 到顶点 2 的路径:
- 0 → 1 → 2 
- 0 → 2

示例 2:

image-20220608192240061

输入:n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], start = 0, end = 5
输出:false
解释:不存在由顶点 0 到顶点 5 的路径.

提示:

  • 1 <= n <= 2 * 10^5
  • 0 <= edges.length <= 2 * 10^5
  • edges[i].length == 2
  • 0 <= ui, vi <= n - 1
  • ui != vi
  • 0 <= start, end <= n - 1
  • 不存在双向边
  • 不存在指向顶点自身的边

解题

方法一:数学 斜率

思路

使用并查集模板完成合并后查询给出的两点间有无连接即可。

代码

class Solution {
    public boolean validPath(int n, int[][] edges, int source, int destination) {
        UnionFind uf = new UnionFind(n);
        for (int[] edge : edges) {  
            uf.union(edge[0], edge[1]);
            if (uf.isConnected(source, destination)) return true;
        }
        return uf.isConnected(source, destination);
    }

    static class UnionFind {
        public int groups;
        private int[] root;
        private int[] rank;

        public UnionFind() {}
        
        public UnionFind(int size) {
            groups = size;
            root = new int[size];
            rank = new int[size];
            for (int i = 0; i < size; i++) {
                root[i] = i;
                rank[i] = 1;
            }
        }

        public void union(int p, int q) {
            int rootP = find(p);
            int rootQ = find(q);
            if (rootP == rootQ) return;
            if (rank[rootP] > rank[rootQ]) {
                root[rootQ] = rootP;
            } else if (rank[rootP] < rank[rootQ]) {
                root[rootP] = rootQ;
            } else {
                root[rootQ] = rootP;
                rank[rootP]++;
            }
            groups--;
        }
        
        public int find(int n) {
            return n == root[n] ? n : (root[n] = find(root[n]));
        }
        
        public boolean isConnected(int p, int q) {
            return find(p) == find(q);
        }
    }
}

优化

不用按秩合并的并查集更快

class Solution {
    private int[] root;

    public boolean validPath(int n, int[][] edges, int source, int destination) {
        root = new int[n];
        for (int i = 0 ; i < n; i++) root[i] = i;
        for (int[] edge : edges) {
            union(edge[0], edge[1]);
            if (find(source) == find(destination)) return true;
        }
        return find(source) == find(destination);
    }

    private void union(int p, int q) {
        root[find(p)] = find(q);
    }

    private int find(int n) {
        return root[n] == n ? n : (root[n] = find(root[n]));
    }
}
0

评论区