Leetcode200. Number of Islands

Leetcode200. Number of Islands

Given a 2d grid map of '1’s (land) and '0’s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

Input:
11110
11010
11000
00000

Output: 1

Example 2:

Input:
11000
11000
00100
00011

Output: 3

思路一 标记法(BFS DFS)

遍历二维数组,然后遇到 1 的时候,把当前的 1 以及它周围的所有 1 都标记成一个字符,记录遇到了几次 1,就代表有几个岛屿。

[1] 1 0 0 0
 1  1 0 0 0
 0 0 1 0 0
 0 0 0 1 1
当前遇到了 1, count = 1;
把当前的 1 和它周围的 1 标记为 2
2 2 0 0 0
2 2 0 0 0
0 0 1 0 0
0 0 0 1 1

2 2  0  0 0
2 2  0  0 0
0 0 [1] 0 0
0 0  0  1 1
遇到下一个 1, count = 2;
把当前的 1 和它周围的 1 标记为 2
2 2 0 0 0
2 2 0 0 0
0 0 2 0 0
0 0 0 1 1   

2 2 0  0  0
2 2 0  0  0
0 0 2  0  0
0 0 0 [1] 1  
遇到下一个 1, count = 3;
把当前的 1 和它周围的 1 标记为 2
2 2 0 0 0
2 2 0 0 0
0 0 2 0 0
0 0 0 2 2  

没有 1 了,所以岛屿数是 count = 3 个。
DFS 回溯 栈
public int numIslands(char[][] grid) {
    int count = 0;
    int rows = grid.length;
    if (rows == 0) {
        return 0;
    }
    int cols = grid[0].length;
    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            if (grid[r][c] == '1') {
                count++;
                marked(r, c, rows, cols, grid);
            }
        }
    }
    return count;
}

private void marked(int r, int c, int rows, int cols, char[][] grid) {
    if (r == -1 || c == -1 || r == rows || c == cols || grid[r][c] != '1') {
        return;
    }
    //当前 1 标记为 2
    grid[r][c] = '2';

    //向上下左右扩展
    marked(r + 1, c, rows, cols, grid);
    marked(r, c + 1, rows, cols, grid);
    marked(r - 1, c, rows, cols, grid);
    marked(r, c - 1, rows, cols, grid);
}
BFS 队列
public int numIslands(char[][] grid) {
        int count = 0;
        int rows = grid.length;
        if (rows == 0) {
            return 0;
        }
        int cols = grid[0].length;
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                if (grid[r][c] == '1') {
                    count++;
                    bfs(r, c, rows, cols, grid);
                }
            }
        }
        return count;
    }
 private void bfs(int r, int c, int rows, int cols, char[][] grid) {
        Queue<Integer> queue = new LinkedList<Integer>();
        queue.offer(r * cols + c);
        while (!queue.isEmpty()) {
            int cur = queue.poll();
            int row = cur / cols;
            int col = cur % cols;
            //已经标记过就结束,这句很关键,不然会把一些节点重复加入
            if(grid[row][col] == '2'){
                continue;
            }
            grid[row][col] = '2';
            //将上下左右连通的 1 加入队列
            if (row != (rows - 1) && grid[row + 1][col] == '1') {
                queue.offer((row + 1) * cols + col);
            }
            if (col != (cols - 1) && grid[row][col + 1] == '1') {
                queue.offer(row * cols + col + 1);
            }
            if (row != 0 && grid[row - 1][col] == '1') {
                queue.offer((row - 1) * cols + col);
            }
            if (col != 0 && grid[row][col - 1] == '1') {
                queue.offer(row * cols + col - 1);
            }
        }
 }

思路二 并查集

并查集详解

首先我们把每个节点各作为一类,用它的行数和列数生成一个 id 标识该类。

int node(int i, int j) {
    return i * cols + j;
}

nums 来记录当前有多少个岛屿,初始化的时候每个 1 都认为是一个岛屿,然后开始合并。

遍历每个为 1 的节点,将它的右边和下边的 1 和当前节点合并(这里算作一个优化,不需要像解法一那样上下左右)。每进行一次合并,我们就将 nums 减 1 。

最后返回 nums 即可。

class UnionFind {
    int[] parents;
    int nums;

    public UnionFind(char[][] grid, int rows, int cols) {
        nums = 0;
        // 记录 1 的个数
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (grid[i][j] == '1') {
                    nums++;
                }
            }
        }

        //每一个类初始化为它本身
        int totalNodes = rows * cols;
        parents = new int[totalNodes];
        for (int i = 0; i < totalNodes; i++) {
            parents[i] = i;
        }
    }

    void union(int node1, int node2) {
        int root1 = find(node1);
        int root2 = find(node2);
        //发生合并,nums--
        if (root1 != root2) {
            parents[root2] = root1;
            nums--;
        }
    }

    int find(int node) {
        while (parents[node] != node) {
            parents[node] = parents[parents[node]];
            node = parents[node];
        }
        return node;
    }

    int getNums() {
        return nums;
    }
}

int rows;
int cols;

public int numIslands(char[][] grid) {
    if (grid.length == 0)
        return 0;

    rows = grid.length;
    cols = grid[0].length;
    UnionFind uf = new UnionFind(grid, rows, cols);

    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            if (grid[row][col] == '1') {
                // 将下边右边的 1 节点和当前节点合并
                if (row != (rows - 1) && grid[row + 1][col] == '1') {
                    uf.union(node(row, col), node(row + 1, col));
                }
                if (col != (cols - 1) && grid[row][col + 1] == '1') {
                    uf.union(node(row, col), node(row, col + 1));
                }
            }
        }
    }
    return uf.getNums();

}

int node(int i, int j) {
    return i * cols + j;
}
发布了82 篇原创文章 · 获赞 7 · 访问量 4986

猜你喜欢

转载自blog.csdn.net/magic_jiayu/article/details/104338215