剑指 Offer II 116. 省份数量(547. 省份数量)

题目:

 

 

 

思路:

【1】深度优先搜索的方式

【2】广度优先搜索的方式

【3】并查集的方式

代码展示:

并查集的方式:

//时间1 ms击败87.49%
//内存42.4 MB击败22.88%
class Solution {
    public int findCircleNum(int[][] isConnected) {
        if (isConnected == null || isConnected.length == 0) {
            return 0;
        }

        int n = isConnected.length;
        UnionFind uf = new UnionFind(n);
        for(int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (isConnected[i][j] == 1) {
                    uf.union(i, j);
                }
            }
        }

        return uf.getCount();
    }

    class UnionFind {
        int root[];
        int rank[];
        int count;

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

        int find(int x) {
            if (x == root[x]) {
                return x;
            }
            return root[x] = find(root[x]);
        }

        void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX != rootY) {
                if (rank[rootX] > rank[rootY]) {
                    root[rootY] = rootX;
                } else if (rank[rootX] < rank[rootY]) {
                    root[rootX] = rootY;
                } else {
                    root[rootY] = rootX;
                    rank[rootX] += 1;
                }
                count--;
            }
        };

        int getCount() {
            return count;
        }
    }
}

//时间1 ms击败87.49%
//内存42.1 MB击败68.65%
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int cities = isConnected.length;
        int[] parent = new int[cities];
        for (int i = 0; i < cities; i++) {
            parent[i] = i;
        }
        for (int i = 0; i < cities; i++) {
            for (int j = i + 1; j < cities; j++) {
                if (isConnected[i][j] == 1) {
                    union(parent, i, j);
                }
            }
        }
        int provinces = 0;
        for (int i = 0; i < cities; i++) {
            if (parent[i] == i) {
                provinces++;
            }
        }
        return provinces;
    }

    public void union(int[] parent, int index1, int index2) {
        parent[find(parent, index1)] = find(parent, index2);
    }

    public int find(int[] parent, int index) {
        if (parent[index] != index) {
            parent[index] = find(parent, parent[index]);
        }
        return parent[index];
    }
}

广度优先搜索的方式:

//时间5 ms击败13.71%
//内存42.1 MB击败76.4%
//时间复杂度:O(n^2),其中 n 是城市的数量。需要遍历矩阵 isConnected 中的每个元素。
//空间复杂度:O(n),其中 n 是城市的数量。
//需要使用数组 visited 记录每个城市是否被访问过,数组长度是 n,广度优先搜索使用的队列的元素个数不会超过 n。
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int cities = isConnected.length;
        boolean[] visited = new boolean[cities];
        int provinces = 0;
        Queue<Integer> queue = new LinkedList<Integer>();
        //这里其实和深度遍历一样每个节点都要检查一次
        for (int i = 0; i < cities; i++) {
            if (!visited[i]) {
                queue.offer(i);
                //这里的意义便是跟递归一样,将能达到的地方又收集回队列,持续标记完
                //相当于将递归变为循环
                while (!queue.isEmpty()) {
                    int j = queue.poll();
                    visited[j] = true;
                    for (int k = 0; k < cities; k++) {
                        if (isConnected[j][k] == 1 && !visited[k]) {
                            queue.offer(k);
                        }
                    }
                }
                provinces++;
            }
        }
        return provinces;
    }
}

深度优先搜索的方式:

//时间1 ms击败87.49%
//内存42.4 MB击败21.93%
//时间复杂度:O(n^2),其中 n 是城市的数量。需要遍历矩阵 n 中的每个元素。
//空间复杂度:O(n),其中 n 是城市的数量。
//需要使用数组 visited 记录每个城市是否被访问过,数组长度是 n,递归调用栈的深度不会超过 n。
class Solution {
    //利用递归,每遍历完一整串相连的节点,统计的岛屿数量才会加1
    //辅以变量visited记录是否被遍历过(可以用int类型替代布尔类型,节约空间)
    public int findCircleNum(int[][] isConnected) {
        int cities = isConnected.length;
        boolean[] visited = new boolean[cities];
        int provinces = 0;
        for (int i = 0; i < cities; i++) {
            if (!visited[i]) {
                dfs(isConnected, visited, cities, i);
                provinces++;
            }
        }
        return provinces;
    }

    public void dfs(int[][] isConnected, boolean[] visited, int cities, int i) {
        for (int j = 0; j < cities; j++) {
            if (isConnected[i][j] == 1 && !visited[j]) {
                visited[j] = true;
                dfs(isConnected, visited, cities, j);
            }
        }
    }
}

 

posted @ 2023-04-23 12:12  忧愁的chafry  阅读(21)  评论(0编辑  收藏  举报