目录
- 1.题目
- 2.思路
- 3.代码实现(Java)
1.题目
给你一个整数 n ,表示一张 无向图 中有 n 个节点,编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条无向边。请你返回无法互相到达的不同点对数目。
示例 1:

输入:n = 3, edges = [[0,1],[0,2],[1,2]]
 输出:0
 解释:所有点都能互相到达,意味着没有点对无法互相到达,所以我们返回 0。
示例 2:

输入:n = 7, edges = [[0,2],[0,5],[2,4],[1,6],[5,4]]
 输出:14
 解释:总共有 14 个点对互相无法到达:
 [[0,1],[0,3],[0,6],[1,2],[1,3],[1,4],[1,5],[2,3],[2,6],[3,4],[3,5],[3,6],[4,6],[5,6]]
 所以我们返回 14。
提示:
 1 <= n <= 105
 0 <= edges.length <= 2 * 105
 edges[i].length == 2
 0 <= ai, bi < n
 ai != bi
 不会有重复边。
2.思路
(1)并查集
(2)DFS
3.代码实现(Java)
//思路1————并查集
class Solution {
    public long countPairs(int n, int[][] edges) {
        UnionFind uf = new UnionFind(n);
        for (int[] edge : edges) {
            uf.union(edge[0], edge[1]);
        }
        long res = 0;
        for (int i = 0; i < n; i++) {
            res += n - uf.getSize(uf.find(i));
        }
        return res / 2;
    }
}
class UnionFind {
    // parent[x] 表示节点 x 的父节点
    int[] parent;
    // sizes[x] 表示根节点 x 所在的树的顶点总数
    int[] sizes;
    public UnionFind(int n) {
        parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
        sizes = new int[n];
        Arrays.fill(sizes, 1);
    }
    public int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }
    public void union(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            if (sizes[rootX] > sizes[rootY]) {
                parent[rootY] = rootX;
                sizes[rootX] += sizes[rootY];
            } else {
                parent[rootX] = rootY;
                sizes[rootY] += sizes[rootX];
            }
        }
    }
    public int getSize(int x) {
        return sizes[x];
    }
}
//思路2————DFS
class Solution {
    List<Integer>[] graph;
    boolean[] visited;
    public long countPairs(int n, int[][] edges) {
        graph = buildGraph(n, edges);
        visited = new boolean[n];
        long res = 0;
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                long cnt = dfs(i);
                res += cnt * (n - cnt);
            }
        }
        return res / 2;
    }
    //通过 DFS 计算当前顶点 u 所在的连通分量的顶点数
    public long dfs(int u) {
        visited[u] = true;
        int cnt = 1;
        for (int v : graph[u]) {
            if (!visited[v]) {
                cnt += dfs(v);
            }
        }
        return cnt;
    }
    //构造邻接表
    public List<Integer>[] buildGraph(int n, int[][] edges) {
        List<Integer>[] graph = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            graph[i] = new ArrayList<>();
        }
        for (int[] edge : edges) {
            int u = edge[0];
            int v = edge[1];
            graph[u].add(v);
            graph[v].add(u);
        }
        return graph;
    }
}



















