给定一个由 '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相当于二维数组的第几列。其他的就没什么了,也是和上面其他几种解法一样,遍历他的上下左右网格。