在leetcode里的深度优先遍历的题目集中,有很多题几乎有着相同的解题思路,其中的岛屿问题就是如此,对应的题目有被围绕的区域,岛屿数量,岛屿的最大面积和统计封闭岛屿的数目,水域大小。在深度优先遍历的时候,往往有个难点就是如何记录当前已经被访问过的节点,如果不做处理的话,很有可能会造成递归,常规的解题思路是用一个visited数组来表示是否已经访问,它有个好处就是不改变原有数据里面的状态,但是同时额外带来些空间消耗。但是在解岛屿问题的时候,我们可能会发现通过直接更改访问节点的状态,可以使我们程序不重复访问某个节点,并且思路也比带visited访问的更加清晰。现已岛屿的最大面积为例,进行介绍
原题:
给定一个包含了一些 0 和 1 的非空二维数组 grid 。
一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)
示例 1:
[[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 。
思路:如何来更改我们的访问节点,来使后面的程序不重复访问呢,假如我们访问了一个值为1的陆地节点,我们肯定要访问它的上下左右四个节点,为了不重复访问,在记完面积后,可以将其值更改为0,改为水域状态,这样,就可达到不重复访问的效果了,代码实现如下:
var dfs = function(grid,x,y){
if(x<0||x>=grid.length||y<0||y>=grid[0].length||grid[x][y]==0){
return 0;
}
let cnt = 1;
grid[x][y]=0;
cnt+=dfs(grid,x+1,y);
cnt+=dfs(grid,x-1,y);
cnt+=dfs(grid,x,y+1);
cnt+=dfs(grid,x,y-1);
return cnt;
}
var maxAreaOfIsland = function(grid) {
if(grid.length==0){
return 0;
}
let height = grid.length;
let width = grid[0].length;
let maxCnt = 0;
for(let i=0;i
这是岛屿问题的基础版,比较容易,我们再来看看进阶版
被围绕的区域,题目如下:
给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。
找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
示例:
X X X X
X O O X
X X O X
X O X X
运行你的函数后,矩阵变为:
X X X X
X X X X
X X X X
X O X X
思路:有点像围棋哈哈,这道题有点区别就是只访问处于边界的O结点和所有与边界点相邻的O结点,只要将活的节点标注出来,那么剩余还为O的节点则是死节点。代码实现如下:
function dfs(board,x,y){
if(x<0||x>=board.length||y<0||y>=board[0].length||board[x][y]!= 'O'){
return ;
}
board[x][y] = 'A'; // 访问边界上的O节点,将其状态改为A,与死节点O做区分
dfs(board,x+1,y);
dfs(board,x-1,y);
dfs(board,x,y+1);
dfs(board,x,y-1);
}
var solve = function(board) {
if(board.length==0){
return [];
}
let height = board.length;
let width = board[0].length;
for(let i=0;i
这样的代码几乎是种模板,可以解决力扣上很多相似的问题。