跳转至

200. 岛屿数量

200. 岛屿数量 - Medium

Description

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

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

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

这里有三种解法,一种是 BFS,一种是 DFS,还有一种就是利用并查集的特性了。

Solution

BFS 解法就是在每个坐标优先向四个方向扩散。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
    public int numIslands(char[][] grid) {
        int count = 0;
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[0].length; j++) {
                if(grid[i][j] == '1'){
                    bfs(grid, i, j);
                    count++;
                }
            }
        }
        return count;
    }
    private void bfs(char[][] grid, int i, int j){
        Queue<int[]> list = new LinkedList<>();
        list.add(new int[] { i, j });
        while(!list.isEmpty()){
            int[] cur = list.remove();
            i = cur[0]; j = cur[1];
            if(0 <= i && i < grid.length && 0 <= j && j < grid[0].length && grid[i][j] == '1') {
                grid[i][j] = '0';
                list.add(new int[] { i + 1, j });
                list.add(new int[] { i - 1, j });
                list.add(new int[] { i, j + 1 });
                list.add(new int[] { i, j - 1 });
            }
        }
    }
}

DFSBFS 不同的就是一次向同一个方向遍历,直到遍历结束后,再向另一个方向遍历。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
    private int rows;
    private int cols;
    private boolean[][] visited;
    int[][] directions = new int[][] {{-1, 0}, {0, 1}, {0, -1}, {1, 0}};
    public int numIslands(char[][] grid) {
        rows = grid.length;
        cols = grid[0].length;
        visited = new boolean[rows][cols];
        int ans = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++){
                if (visited[i][j] || grid[i][j] == '0') continue;
                visited[i][j] = true;
                dfs(i, j, grid);
                ans++;
            }
        }
        return ans;
    }

    private void dfs(int x, int y, char[][] grid) {
        visited[x][y] = true;
        for (int[] d : directions) {
            int newX = x + d[0];
            int newY = y + d[1];
            if (newX >= 0 && newX < rows && newY >= 0 && newY < cols && !visited[newX][newY] && grid[newX][newY] == '1') {
                dfs(newX, newY, grid);
            }
        }
    }
}

利用并查集连通分量的特性,首先可以将相邻的岛屿'1'都连接起来,因为并查集有传递性,所以只用关心两个方向,右和下,将右和下两个方向中的岛屿连接起来。如果遇到'0'的元素,需要记录下来数量。

这样最后执行完毕后,岛屿的数量就是 连通分量的数量 - '0'的数量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Solution {
    private int rows;
    private int cols;
    public int numIslands(char[][] grid) {
        rows = grid.length;
        cols = grid[0].length;
        int zeroes = 0;
        UF uf = new UF(rows * cols);
        int[][] directions = new int[][] {{1,0}, {0,1}};
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++){
                if (grid[i][j] == '0') {
                    zeroes++;
                } else {
                    for (int[] d : directions) {
                        int newR = i + d[0];
                        int newC = j + d[1];
                        if (newR < rows && newC < cols && grid[newR][newC] == '1') {
                            uf.union(i * cols + j, newR * cols + newC);
                        }
                    }
                }
            }
        }
        return uf.count() - zeroes;
    }

    static class UF {
        private int[] parent;
        private int count;
        public UF (int n) {
            parent = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
            count = n;
        }

        public void union(int p, int q) {
            int rootP = find(p);
            int rootQ = find(q);

            if (rootP == rootQ) return;
            parent[rootQ] = rootP;
            this.count--;
        }

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

        public int count() {
            return this.count;
        }
    }
}

评论

回到页面顶部