一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
[[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
对于上面这个给定矩阵应返回 6。注意答案不应该是 11 ,因为岛屿只能包含水平或垂直的四个方向的 1 。
示例 2:
[[0,0,0,0,0,0,0,0]]
对于上面这个给定的矩阵, 返回 0。
注意: 给定的矩阵grid 的长度和宽度都不超过 50。
对于这道题目还是采用之前的分析方式:
-
访问路径:节点中相邻的1构成一条路径。0 直接无视。
-
起点条件:二维数组的每个点都可以当作起点。所以两个 for 循环来进行调用。
-
递归参数:当前访问的节点位置(x,y),二维数组表,从表中查找下一个节点
-
终结条件:到达二维数组的边界,节点为0
-
访问标志:需要,不可重复访问;可以将访问过的节点置为0,避免再次访问,重复计算。
-
剪枝:只有在节点等于1的时候,才调用dfs。这样可以减少调用次数。
题目解答如下:
class Solution {
public int maxAreaOfIsland(int[][] grid) {
if (grid == null || grid.length <1 || grid[0].length<1) {
return 0;
}
int rx = grid.length;
int cy = grid[0].length;
int max = 0;
for (int x =0; x< rx; x++) {
for (int y= 0;y<cy; y++) {
if (grid[x][y]==1) { //只有节点等于1才调用,这里就可以算作是剪枝,算法的优化
int num = dfs(grid,x,y);
max = Math.max(max, num);
}
}
}
return max;
}
// 递归参数:节点位置x,y, 二维数组
private int dfs (int[][] grid, int x, int y){
int rx = grid.length;
int cy = grid[0].length;
// 边界条件,节点为0
if (x >= rx || x < 0 || y>=cy || y<0 || grid[x][y]==0 ) {
return 0;
}
// 直接修改原数组来标记已访问
grid[x][y]=0;
// 每次递归就表示面积多了一块
int num = 1;
// 每个节点有四种不同的选择方向
num += dfs(grid, x-1, y);
num += dfs(grid, x, y-1);
num += dfs(grid, x+1, y);
num += dfs(grid, x, y+1);
return num;
}
}
200. 岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
// 输入:
11110
11010
11000
00000
// 输出: 1
示例 2:
// 输入:
11000
11000
00100
00011
// 输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
可以发现,这道题目与前面的题目很类似,关于 dfs 规则这里就不在分析了,留给大家自己去分析。
题目解答如下:
class Solution {
public int numIslands(char[][] grid) {
if (grid == null || grid.length < 1 || grid[0].length<1) {
return 0;
}
int num = 0;
int rx = grid.length;
int cy = grid[0].length;
// 起始点
for (int x =0;x<rx;x++) {
for (int y =0;y<cy;y++) {
// 题目要求,'0'不符合路径条件
if (grid[x][y]=='1') {
dfs(grid,x,y);
num++;
}
}
}
return num;
}
// 递归条件
private void dfs(char[][] grid, int x, int y) {
int rx = grid.length;
int cy = grid[0].length;
// 终结条件
if (x<0 || x>=rx || y<0 || y>= cy || grid[x][y] == '0') {
return;
}
// 访问方向实质是由访问路径来决定的,就是你得想清楚怎么才算一条路径
grid[x][y]='0';
dfs(grid,x-1,y);
dfs(grid,x,y-1);
dfs(grid,x+1,y);
dfs(grid,x,y+1);
return ;
}
}
到这里,深度优先搜索的理论和实践就讲完了,相信看到这里的小伙伴应该也掌握了其算法的原理,以及如何去书写。
参考文章
基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)