LeetCode破解之栈的岛屿数量

209 阅读1分钟

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

题目描述

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid = [ ["1","1","1","1","0"], ["1","1","0","1","0"], ["1","1","0","0","0"], ["0","0","0","0","0"] ] 输出:1

示例 2:

输入:grid = [ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"] ] 输出:3

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 '0' 或 '1'

解法1:并查集

思路:

  • 1不代表岛屿,岛屿可以由1个或者很多个1组成
  • 水平方向和/或竖直方向上相邻的陆地链接: 意思是如果某个'1'和 水平和/或竖竖直方向 的其他1邻接,说明这个1不是独立的,属于某一片岛屿
  • 只有完全没有邻接1的"一片1"才属于另一个独立岛屿,也就是岛屿数+1
    class Solution {
        public int numIslands(char[][] grid) {
            DisjointSet djs = new DisjointSet(grid.length * grid[0].length);
            Set<Integer> island = new HashSet<>();
            for (int i = 0; i < grid.length; i++) {
                for (int j = 0; j < grid[i].length; j++) {
                    if (grid[i][j] == '1') {
                        int djsIndex = calIndex(grid, i, j);
                        union(grid, djsIndex, i - 1, j, djs);
                        union(grid, djsIndex, i, j - 1, djs);
                        union(grid, djsIndex, i + 1, j, djs);
                        union(grid, djsIndex, i, j + 1, djs);
                        island.add(djsIndex);
                    }
                }
            }

            Set<Integer> res = new HashSet<>();
            for (Integer integer : island) {
                res.add(djs.find(integer));
            }
            return res.size();
        }

        private void union(char[][] grid, int index, int i, int j, DisjointSet djs) {
            if (canVisited(grid, i, j) && grid[i][j] == '1') {
                djs.union(index, calIndex(grid, i, j));
            }
        }

        private boolean canVisited(char[][] grid, int i, int j) {
            return i >= 0 && i < grid.length && j >= 0 && j < grid[i].length;
        }

        public int calIndex(char[][] grid, int i, int j) {
            return i * grid[i].length + j;
        }

        class DisjointSet {
            public DisjointSet(int count) {
                this.count = count;
                this.parent = new int[count];
                for (int i = 0; i < parent.length; i++) {
                    parent[i] = i;
                }
            }

            final int[] parent;
            int count = 0;


            public int find(int i) {
                while (parent[i] != i) {
                    parent[i] = parent[parent[i]];
                    i = parent[i];
                }
                return parent[i];
            }

            public void compress() {
                for (int i = 0; i < parent.length; i++) {
                    find(i);
                }
            }

            public int union(int i, int j) {
                int pi = find(i);
                int pj = find(j);
                if (pi != pj) {
                    parent[pj] = pi;
                    count--;
                }
                return pi;
            }
        }

解法二:DFS

思路:就是通过遍历每一个格子,然后深度递归所有的周围点,遍历之后置2,然后继续遍历周围的格子,如果遇到2或0就结束(即return),知道没有了,就返回主函数,相当于遍历了一遍这个陆地,res++。然后再继续找下一个格子进行遍历,直遍历完毕。

class Solution {
    public int numIslands(char[][] grid) {
        if(grid == null) return 0;

        int n = grid.length;
        int m = grid[0].length;
        int res = 0;
        boolean[][]  marked = new boolean[n][m];

        if(n == 0 || m==0) return 0;

        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(grid[i][j] == '1' && !marked[i][j]){
                    dfs(grid,marked,i,j);
                    res++;
                }
            }
        }

        return res;
    }

    public void dfs(char[][] arr,boolean[][] marked,int x,int y){
        marked[x][y] = true;

        int n = arr.length;
        int m = arr[0].length;
        
        //上
        if(x>0 && !marked[x-1][y] && arr[x-1][y] == '1'){
            dfs(arr,marked,x-1,y);
        }

        //下
        if(x<n-1 && !marked[x+1][y] && arr[x+1][y] == '1'){
            dfs(arr,marked,x+1,y);
        }

        //左
        if(y>0 && !marked[x][y-1] && arr[x][y-1] == '1'){
            dfs(arr,marked,x,y-1);
        }
        

        //右
        if(y<m-1 && !marked[x][y+1] && arr[x][y+1] == '1'){
            dfs(arr,marked,x,y+1);
        }
        return;
    }
}