292,岛屿数量

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1

示例 2:

输入:
11000
11000
00100
00011

输出: 3

答案:

 1public int numIslands(char[][] grid) {
2    int count = 0;
3    if (grid.length == 0)
4        return 0;
5    for (int i = 0; i < grid.length; i++) {
6        for (int j = 0; j < grid[0].length; j++)
7            if (grid[i][j] == '1') {
8                DFSMarking(grid, i, j);
9                ++count;
10            }
11    }
12    return count;
13}
14
15private void DFSMarking(char[][] grid, int i, int j) {
16    if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] != '1')
17        return;
18    grid[i][j] = '0';
19    DFSMarking(grid, i + 1, j);
20    DFSMarking(grid, i - 1, j);
21    DFSMarking(grid, i, j + 1);
22    DFSMarking(grid, i, j - 1);
23}

解析:

题目说了,网格的四边都被水包围,所以网格中只要不全是0,就肯定有岛屿,这里岛屿的定义是他的上下左右都是水。代码中第7行,如果当前网格是1,就会调用DFSMarking,DFSMarking使用递归的方法,然后再遍历他的右左下上四个方向,原理比较简单,下面再来看种解法

 1static int[] dx = {-1, 0, 0, 1};
2static int[] dy = {0, 1, -1, 0};
3
4public static int numIslands(char[][] grid) {
5    if (grid == null || grid.length == 0)
6        return 0;
7    int islands = 0;
8    for (int i = 0; i < grid.length; i++) {
9        for (int j = 0; j < grid[i].length; j++) {
10            if (grid[i][j] == '1') {
11                explore(grid, i, j);
12                islands++;
13            }
14        }
15    }
16    return islands;
17}
18
19public static void explore(char[][] grid, int i, int j) {
20    grid[i][j] = '0';
21    for (int d = 0; d < dx.length; d++) {
22        if (i + dy[d] < grid.length && i + dy[d] >= 0 && j + dx[d] < grid[0].length && j + dx[d] >= 0 && grid[i + dy[d]][j + dx[d]] == '1') {
23            explore(grid, i + dy[d], j + dx[d]);
24        }
25    }
26}

上面两种写法的本质并没有变,原理还都是一样的。就是找到一个为1的网格,然后再递归的方式遍历他的上下左右四个方向,注意递归的时候这两种方法都会有一些边界的判断。或者还可以再换一种解法

 1public int numIslands(char[][] grid) {
2    int islands = 0;
3    for (int i = 0; i < grid.length; i++)
4        for (int j = 0; j < grid[i].length; j++)
5            islands += sink(grid, i, j);
6    return islands;
7}
8
9int[] d = {0, 1, 0, -1, 0};
10
11int sink(char[][] grid, int i, int j) {
12    if (i < 0 || i == grid.length || j < 0 || j == grid[i].length || grid[i][j] == '0')
13        return 0;
14    grid[i][j] = '0';
15    for (int k = 0; k < 4; k++)
16        sink(grid, i + d[k], j + d[k + 1]);
17    return 1;
18}

我们再来看一个不使用递归解法的方式

 1public int numIslands(char[][] grid) {
2    int count = 0;
3    for (int i = 0; i < grid.length; i++)
4        for (int j = 0; j < grid[0].length; j++) {
5            if (grid[i][j] == '1') {
6                bfsFill(grid, i, j);
7                count++;
8            }
9        }
10    return count;
11}
12
13private void bfsFill(char[][] grid, int x, int y) {
14    grid[x][y] = '0';
15    int n = grid.length;
16    int m = grid[0].length;
17    LinkedList<Integer> queue = new LinkedList<>();
18    int code = x * m + y;
19    queue.offer(code);
20    while (!queue.isEmpty()) {
21        code = queue.poll();
22        int i = code / m;
23        int j = code % m;
24        if (i > 0 && grid[i - 1][j] == '1')    //上
25        {
26            queue.offer((i - 1) * m + j);
27            grid[i - 1][j] = '0';
28        }
29        if (i < n - 1 && grid[i + 1][j] == '1')  //下
30        {
31            queue.offer((i + 1) * m + j);
32            grid[i + 1][j] = '0';
33        }
34        if (j > 0 && grid[i][j - 1] == '1')  //左
35        {
36            queue.offer(i * m + j - 1);
37            grid[i][j - 1] = '0';
38        }
39        if (j < m - 1 && grid[i][j + 1] == '1')  //右
40        {
41            queue.offer(i * m + j + 1);
42            grid[i][j + 1] = '0';
43        }
44    }
45}

这里的code其实相当于把二维数组转化为了一维数组来存储,代码不难理解,比较难理解的估计就是一些计算,while循环中的i相当于二维数组的第几行,j相当于二维数组的第几列。其他的就没什么了,也是和上面其他几种解法一样,遍历他的上下左右网格。

上一篇:LeetCode——292. Nim 游戏(Java)


下一篇:LeetCode_292. Nim Game