LeetCode-DFS
DFS,Depth First Search,深度优先搜索,是图论中一个遍历搜索算法
200.岛屿数量
在刚开始学习数据结构图论中的DFS时,是使用邻接数组存储结构,借助visited数组标记某个顶点是否被访问过,然后对图中每一个未被访问的节点进行DFS深度优先遍历,每遍历到一个顶点就标记该节点被访问,当所有顶点均被访问,即visited数组中所有元素值都为1时,遍历结束
而在实际解题应用中,有时候可以不用借助visited数组来达到标记被访问的效果,节省空间。例如这道题中,题目说到岛屿总是被水包围,所以只要遍历到了"1",说明一定会对应地存在一个岛屿,那么跟这个"1"在同一个岛屿上的其它"1"就不需要被遍历了,所以对这个"1"进行DFS将与其在同一个岛屿上的“1”改为"0"即可,后续就不会再对那些点进行遍历,达到标记的目的
public int numIslands(char[][] grid) {
int res = 0;
for(int i = 0;i < grid.length;i++){
for(int j = 0;j < grid[0].length;j++){
if(grid[i][j] == '1'){
res++;
dfs(grid,i,j);
}
}
}
return res;
}
public void dfs(char[][] grid,int i,int j){
//递归边界 : 索引越界或遍历到了"0"
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0') return;
//标记为"0"
grid[i][j] = '0';
//根据"每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成",对上下左右的相邻顶点进行dfs
dfs(grid,i - 1,j);
dfs(grid,i + 1,j);
dfs(grid,i,j + 1);
dfs(grid,i,j - 1);
}
1254.统计封闭岛屿的数量
从题意可以看出,只要存在在矩阵的四条边上的土地的岛屿都不是封闭岛屿,那么继续沿用上面200题的思想解题,而不同的地方在于,要先把矩阵四条边上的土地所在的岛屿先置为"1",变为水,然后再对剩下的区域进行查找岛屿数量的操作
public int closedIsland(int[][] grid) {
int row = grid.length;
int column = grid[0].length;
int res = 0;
//先排除掉四条边上的岛屿
for(int i = 0;i < row;i++){
dfs(grid,i,0);
dfs(grid,i,column - 1);
}
for(int i = 0;i < column;i++){
dfs(grid,0,i);
dfs(grid,row - 1,i);
}
//再进行200题的查找岛屿数量操作
for(int i = 0;i < row;i++){
for(int j = 0;j < column;j++){
if(grid[i][j] == 0){
res++;
dfs(grid,i,j);
}
}
}
return res;
}
public void dfs(int[][] grid,int i,int j){
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 1) return;
grid[i][j] = 1;
dfs(grid,i - 1,j);
dfs(grid,i + 1,j);
dfs(grid,i,j + 1);
dfs(grid,i,j - 1);
}
695.岛屿的最大面积
同样的,继续沿用200的做法,而不同的地方在于,找出岛屿的同时还要记录岛屿的面积,即土地数,所以要把dfs方法改为能计算岛屿面积的方法
public int maxAreaOfIsland(int[][] grid) {
int res = 0;
for(int i = 0;i < grid.length;i++){
for(int j = 0;j < grid[0].length;j++){
if(grid[i][j] == 1){
//与200题相比,不是每dfs一个岛屿就记录一个数量,
//而是通过dfs得到岛屿的面积然后记录最大的面积
res = Math.max(res,dfs(grid,i,j));
}
}
}
return res;
}
public int dfs(int[][] grid,int i,int j){
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0;
grid[i][j] = 0;
//递归的思路:要求当前土地(i,j)所在的岛屿的面积,则等于1加上下左右相邻土地的总面积
return 1 + dfs(grid,i - 1,j) +
dfs(grid,i + 1,j) +
dfs(grid,i,j + 1) +
dfs(grid,i,j - 1);
}
1020.飞地的数量
这道题结合了1254题跟695题,要先像695题一样排除掉边界的岛屿,然后统计剩下的所有符合"飞地"条件的岛屿的单元格的总数量
public int numEnclaves(int[][] grid) {
int row = grid.length;
int column = grid[0].length;
int res = 0;
for(int i = 0;i < row;i++){
dfs(grid,i,0);
dfs(grid,i,column - 1);
}
for(int i = 0;i < column;i++){
dfs(grid,0,i);
dfs(grid,row - 1,i);
}
for(int i = 0;i < row;i++){
for(int j = 0;j < column;j++){
if(grid[i][j] == 1){
//计算每个“飞地“的面积,即单元格数量,然后叠加得到最终的总单元格数量
res += dfs(grid,i,j);
}
}
}
return res;
}
//统计一个岛屿上的单元格的数量,即一个岛屿的面积
public int dfs(int[][] grid,int i,int j){
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0;
grid[i][j] = 0;
return 1 + dfs(grid,i - 1,j) +
dfs(grid,i + 1,j) +
dfs(grid,i,j + 1) +
dfs(grid,i,j - 1);
}
1905.统计子岛屿
题目要求子岛屿的数量,那就先把grid2中不符合子岛屿条件的岛屿先“淹没掉”,即都变成“0“,那么剩下的岛屿就都是子岛屿了,再进行统计岛屿数量的操作就可以了
public int countSubIslands(int[][] grid1, int[][] grid2) {
int row = grid2.length;
int column = grid2[0].length;
for(int i = 0;i < row;i++){
for(int j = 0;j < column;j++){
//先排除掉不符合子岛屿条件的岛屿
if(grid2[i][j] == 1 && grid1[i][j] == 0){
dfs(grid2,i,j);
}
}
}
//像200题一样统计岛屿数量
int res = 0;
for(int i = 0;i < row;i++){
for(int j = 0;j < column;j++){
if(grid2[i][j] == 1){
res++;
dfs(grid2,i,j);
}
}
}
return res;
}
public void dfs(int[][] grid,int i,int j){
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return;
grid[i][j] = 0;
dfs(grid,i - 1,j);
dfs(grid,i + 1,j);
dfs(grid,i,j + 1);
dfs(grid,i,j - 1);
}