力扣200题岛屿数量

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

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

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

难度:Medium

示例:

 

 方法一(并查集):

class Solution {
    public int numIslands(char[][] grid) {
        if(grid == null || grid.length == 0){
            return 0;
        }
        UnionFind uf = new UnionFind(grid);
        int row = grid.length;
        int col = grid[0].length;
        int water = 0;//水域面积
        //方向数组
        List<int[]> direction = new ArrayList<>();
        direction.add(new int[]{0,1});
        direction.add(new int[]{0,-1});
        direction.add(new int[]{1,0});
        direction.add(new int[]{-1,0});
        for(int i = 0;i<row;++i){
            for(int j = 0;j<col;++j){
                if(grid[i][j] == '0'){//水域面积加一
                    water++;
                }else{
                    //遍历方向数组,模拟搜寻i,j点的上下左右方向
                    for(int[] loc : direction){
                        int r = i + loc[0];
                        int c = j + loc[1];
                        if(r >= 0 && r < row && c >=0 && c < col && grid[r][c] == '1'){
                            uf.union(r*col + c,i*col + j);//二维坐标转换为一维
                            //例如(x,y)对应的一维坐标为x * col + y,(1,2)对应为1*4 + 2 = 6
                        }
                    }
                }
            }
        }
        return uf.getCount() - water;//合并完之后的count减去水域面积即为岛屿数量
    }

    //构建并查集
    class UnionFind{
        //单元总数,初始值为grid矩阵元素总数
        int count;
        //表示子父节点关系的一维数组
        int[] parent;
        //构造方法
        public UnionFind(char[][] grid){
            int row = grid.length;
            int col = grid[0].length;
            count = row * col;
            parent = new int[row * col];
            //将一维数组中每个元素初始化为对应索引的值,代表矩阵中每个元素的父节点都为其本身
            for(int i = 0;i<row * col;++i){
                parent[i] = i;
            }

        }
        //递归查找父节点,返回值为x的父节点
        public int find(int x){
            if(x == parent[x]){
                return x;
            }else{
                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){//不相等,代表父节点不一样,需要合并
                parent[rootx] = rooty;
                //合并一次count就减一
                count--;
            }
        }
        public int getCount(){
            return this.count;
        }
    }
}

效率:

 

方法二(广度优先遍历BFS):

class Solution {
    public int numIslands(char[][] grid) {
        if(grid == null || grid.length == 0) return 0;
        int[][] directions = {{0,1},{0,-1},{1,0},{-1,0}};//构建上下左右移动二维数组
        int count = 0;//记录岛屿数量
        int row = grid.length;
        int col = grid[0].length;
        Queue<int[]> queue = new LinkedList<>();//BFS队列
        for(int i = 0;i<row;++i){
            for(int j = 0;j<col;++j){//遍历整个grid
                if(grid[i][j] == '1'){//若此坐标点等于'1',则岛屿数量加1,且将此坐标点加入队列,并扫描上下左右数组
                    count++;//岛屿数量加1
                    queue.offer(new int[]{i,j});//将此坐标点点加入BFS队列
                    while(!queue.isEmpty()){//BFS
                        int size = queue.size();
                        for(int k = 0;k<size;++k){//遍历BFS队列
                            int[] arr = queue.poll();
                            for(int[] dir : directions){//依次遍历上下左右移动数组
                                int newx = arr[0] + dir[0];
                                int newy = arr[1] + dir[1];
                                if(newx >= 0 && newy >= 0 && newx < row && newy < col && grid[newx][newy] == '1'){//若上下左右坐标点都没超出grid范围且此时为'1',则执行以下操作
                                    queue.offer(new int[]{newx,newy});//将此坐标点加入BFS队列
                                    grid[newx][newy] = '0';//将此坐标点改为'0',防止下次遍历到重复计数
                                }
                            }
                        }
                    }
                }
            }
        }
        return count;
    }      
}

效率:

  

方法三(深度优先遍历DFS): 

class Solution {
    public int numIslands(char[][] grid) {
        if(grid == null || grid.length == 0) return 0;
        int count = 0;//岛屿数量
        int row = grid.length;
        int col = grid[0].length;
        for(int i = 0;i<row;++i){
            for(int j = 0;j<col;++j){
                if(grid[i][j] == '1'){//若此坐标点为'1',则执行if块
                    count++;
                    dfs(grid,i,j,row,col);//DFS将此坐标点上下左右改为'0'
                }
            }
        }
        return count;
    }     
    public void dfs(char[][] grid,int i,int j,int row,int col){
        if(i < 0 || j < 0 || i >= row || j >= col || grid[i][j] == '0'){//判断终止条件
            return;
        }
        grid[i][j] = '0';//将当前坐标点改为'0'
        dfs(grid,i+1,j,row,col);//依次修改上下左右坐标点
        dfs(grid,i-1,j,row,col);
        dfs(grid,i,j+1,row,col);
        dfs(grid,i,j-1,row,col);
    } 
}

效率:

  

 

总结:此题三种解法都非常经典,建议都掌握,并多敲几次,达到能够自己立刻码出来的程度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值