一文秒杀所有岛屿题目 :: labuladong的算法小抄 (gitee.io)
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
用DFS算法/BFS算法遍历二维数组,将二维矩阵中的每一个位置看做一个节点,这个节点的上下左右四个位置就是相邻节点,那么整个矩阵就可以抽象成一幅网状的图结构。因为是遍历一幅图,所以遍历的过程中还需要一个 visited 布尔数组防止走回头路。
这道题中没有使用visited数组,而是选择每次遇到岛屿时,都用DFS算法把岛屿淹掉,避免了维护visited数组。
- class Solution {
- public:
- int numIslands(vector
char >>& grid) { - int res=0;
- for(int i=0;i
size();i++) - {
- for(int j=0;j
0].size();j++) - {
- if(grid[i][j]=='1')//grid[i][j]是陆地
- {
- dfs(i,j,grid);
- res++;
- }
- }
- }
- return res;
- }
- //从grid[i][j]开始,把与之相邻的陆地都淹掉
- void dfs(int i,int j,vector
char >>& grid) - {
- int m=grid.size();
- int n=grid[0].size();
- //处理越界
- if(i<0||i>=m||j<0||j>=n)
- {
- return ;
- }
- if(grid[i][j]=='0')//已经是海水了
- {
- return ;
- }
- grid[i][j]='0';//把grid[i][j]淹掉
- //把grid[i][j]的上下左右都淹掉
- dfs(i-1,j,grid);
- dfs(i+1,j,grid);
- dfs(i,j-1,grid);
- dfs(i,j+1,grid);
- }
- };
二维矩阵 grid 由 0 (土地)和 1 (水)组成。岛是由最大的4个方向连通的 0 组成的群,封闭岛是一个 完全 由1包围(左、上、右、下)的岛。
请返回 封闭岛屿 的数目。
示例 1:

输入:grid = [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]] 输出:2 解释: 灰色区域的岛屿是封闭岛屿,因为这座岛屿完全被水域包围(即被 1 区域包围)。
思路:
由题意得,靠边的陆地不算封闭岛屿,所以先用dfs把四条边上的陆地都排除掉,剩下的就是封闭岛屿。
- class Solution {
- public:
- int closedIsland(vector
int >>& grid) { - int m=grid.size();
- int n=grid[0].size();
- int res=0;
- //把边上的岛都淹掉
- for(int i=0;i
- {
- dfs(grid,i,0);//把左边的岛都淹掉
- dfs(grid,i,n-1);//把右边的岛都淹掉
- }
- for(int j=0;j
- {
- dfs(grid,0,j);//把上边的岛都淹掉
- dfs(grid,m-1,j);//把下边的岛都淹掉
- }
- //遍历grid,此时剩下的岛屿都是封闭岛
- for(int i=0;i
- {
- for(int j=0;j
- {
- if(grid[i][j]==0)
- {
- res++;
- dfs(grid,i,j);
- }
- }
- }
- return res;
- }
- //从grid[i][j]开始,把与之相邻的陆地都淹掉
- void dfs(vector
int >>& grid,int i,int j) - {
- int m=grid.size();
- int n=grid[0].size();
- //处理越界
- if(i<0||j<0||i>=m||j>=n)
- {
- return ;
- }
- //已经是海水了
- if(grid[i][j]==1)
- {
- return ;
- }
- //把grid[i][j]淹掉
- grid[i][j]=1;
- //把grid[i][j]的上下左右都淹掉
- dfs(grid,i+1,j);
- dfs(grid,i-1,j);
- dfs(grid,i,j+1);
- dfs(grid,i,j-1);
- }
- };
给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
岛屿的面积是岛上值为 1 的单元格的数目。
计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
示例 1:

输入:grid = [[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
思路:
给dfs设置返回值,记录每次淹没的陆地的面积
- class Solution {
- public:
- int maxAreaOfIsland(vector
int >>& grid) { - int res=0;
- int m=grid.size();
- int n=grid[0].size();
- for(int i=0;i
- {
- for(int j=0;j
- {
- if(grid[i][j]==1)
- {
- int cover=dfs(grid,i,j);
- res=max(cover,res);//选取面积最大的岛屿
- }
- }
- }
- return res;
- }
- //淹没与grid[i][j]相邻的陆地,并返回淹没陆地的面积
- int dfs(vector
int >>& grid,int i,int j) - {
- int m=grid.size();
- int n=grid[0].size();
- if(i<0||j<0||i>=m||j>=n)
- {
- return 0;
- }
- if(grid[i][j]==0)
- {
- return 0;
- }
- grid[i][j]=0;
-
- return dfs(grid,i+1,j)
- +dfs(grid,i-1,j)
- +dfs(grid,i,j+1)
- +dfs(grid,i,j-1)+1;
- }
- };
给你两个 m x n 的二进制矩阵 grid1 和 grid2 ,它们只包含 0 (表示水域)和 1 (表示陆地)。一个 岛屿 是由 四个方向 (水平或者竖直)上相邻的 1 组成的区域。任何矩阵以外的区域都视为水域。
如果 grid2 的一个岛屿,被 grid1 的一个岛屿 完全 包含,也就是说 grid2 中该岛屿的每一个格子都被 grid1 中同一个岛屿完全包含,那么我们称 grid2 中的这个岛屿为 子岛屿 。
请你返回 grid2 中 子岛屿 的 数目 。
示例 1:

输入:grid1 = [[1,1,1,0,0],[0,1,1,1,1],[0,0,0,0,0],[1,0,0,0,0],[1,1,0,1,1]], grid2 = [[1,1,1,0,0],[0,0,1,1,1],[0,1,0,0,0],[1,0,1,1,0],[0,1,0,1,0]]
输出:3
解释:如上图所示,左边为 grid1 ,右边为 grid2 。
grid2 中标红的 1 区域是子岛屿,总共有 3 个子岛屿。
思路:
如果岛屿2中存在一片陆地,在岛屿1的对应位置是海水,那么岛屿2就不是岛屿1的子岛 ,
排除2中肯定不是子岛的岛屿
现在2中剩下的肯定都是子岛,就可以计算子岛数量了
- class Solution {
- public:
- int countSubIslands(vector
int >>& grid1, vectorint >>& grid2) { - int m=grid2.size();
- int n=grid2[0].size();
- //如果岛屿2中存在一片陆地,在岛屿1的对应位置是海水,那么岛屿2就不是岛屿1的子岛
- for(int i=0;i
- {
- for(int j=0;j
- {
- if(grid2[i][j]==1&&grid1[i][j]==0)//淹掉2中肯定不是子岛的岛屿
- {
- dfs(grid2,i,j);
- }
- }
- }
- int res=0;
- for(int i=0;i
//现在2中剩下的肯定都是子岛,计算子岛数量 - {
- for(int j=0;j
- {
- if(grid2[i][j]==1)
- {
- dfs(grid2,i,j);
- res++;
- }
- }
- }
- return res;
- }
- void dfs(vector
int >>& grid2,int i,int j) - {
- int m=grid2.size();
- int n=grid2[0].size();
- if(i<0||j<0||i>=m||j>=n)
- {
- return ;
- }
- if(grid2[i][j]==0)
- {
- return ;
- }
- grid2[i][j]=0;
- dfs(grid2,i+1,j);
- dfs(grid2,i-1,j);
- dfs(grid2,i,j+1);
- dfs(grid2,i,j-1);
- }
- };
给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。
返回执行此操作后,grid 中最大的岛屿面积是多少?
岛屿 由一组上、下、左、右四个方向相连的 1 形成。
示例 1:
输入: grid = [[1, 0], [0, 1]]
输出: 3
解释: 将一格0变成1,最终连通两个小岛得到面积为 3 的岛屿。
示例 2:
输入: grid = [[1, 1], [1, 0]]
输出: 4
解释: 将一格0变成1,岛屿的面积扩大为 4。
示例 3:
输入: grid = [[1, 1], [1, 1]]
输出: 4
解释: 没有0可以让我们变成1,面积依然为 4。
思路:
-
首先dfs找岛屿,找到一块就淹了它,并且给这个岛屿标记一下,存入HashMap(Key:岛屿的序号,Value,岛屿的面积)。给第一块岛屿标记为flag = -1,同时,在找的过程中,把访问到的格子的值改成flag。然后每当找到一块,flag--。有两个好处,第一,每块岛屿都被唯一标记了。第二,因为格子的值改成了小于0的flag,判断格子的值是否<=0就等效于visited数组的功能,使得回溯的过程中不会再访问已经访问过的格子。
-
对于已经标记完岛屿的地图,只需要挨个遍历,找到每个海洋(值为0)的格子,然后试一下上下左右是否可以连通,若联通,就计算一下联通之后的最大面积,更新答案。在这个过程中,需要用set判断上下左右有没有相同的岛屿,即每个岛屿只能加一次。
-
返回最大的答案
例:grid={ 遍历之后----》 grid={
{1,0,1}, {-1,0,-2},
{0,0,0}, {0,0,0},
{0,1,1} {0,-3,-3}
} }
unoedered_map mapping={ ( -1 , 1 ),( -2 , 1 ),( -3 , 2 ) } 。
- class Solution {
- public:
- int largestIsland(vector
int >>& grid) { - unordered_map<int,int> mapping;
- int n=grid.size();
- int flag=-1;//序号从-1开始递减,防止dfs时走回头路
- for(int i=0;i
//将grid中各个岛屿的面积都与序号flag联系起来 - {
- for(int j=0;j
- {
- if(grid[i][j]==1)
- {
- int cover=dfs(grid,i,j,flag);
- mapping[flag]=cover;
- flag--;
- }
- }
- }
- int res=0;
- set<int> s;
- for(int i=0;i
- {
- for(int j=0;j
- {
- int cover=0;
- if(grid[i][j]==0)//假设将grid[i][j]变成陆地
- {
- int up=0,down=0,left=0,right=0;//记录grid[i][j]的上下左右情况
- if(i>0) up=grid[i-1][j];
- if(i
-1) down=grid[i+1][j]; - if(j>0) left=grid[i][j-1];
- if(j
-1) right=grid[i][j+1]; - //加入set中去重
- s.insert(up);
- s.insert(down);
- s.insert(left);
- s.insert(right);
- for(int dir:s)
- {
- if(dir<0)//小于0,那它就是一块陆地
- {
- cover+=mapping[dir];
- }
- }
- s.clear();//存完grid[i][j]的上下左右情况,记得要清空set
- cover++;//加上假设的那块陆地
- }
- res=max(res,cover);//求出最大面积
- }
- }
- if(res==0)//如果grid全是陆地,那么最后res应该为n*n
- {
- res=n*n;
- }
- return res;
- }
-
- int dfs(vector
int >>& grid,int i,int j,int flag) - {
- int n=grid.size();
- if(i>=n||j>=n||i<0||j<0)//超出边界,返回0
- return 0;
- if(grid[i][j]<=0)//如果是海水或者其他已经被淹掉的陆地,那么就返回0
- return 0;
- if(grid[i][j]==1)//如果是陆地,就用flag把它淹掉(用flag标记它)
- grid[i][j]=flag;
- return dfs(grid,i+1,j,flag)+
- dfs(grid,i-1,j,flag)+
- dfs(grid,i,j+1,flag)+
- dfs(grid,i,j-1,flag)+1;
- }
- };
给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。
岛 是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid 中 恰好存在两座岛 。
你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛 。
返回必须翻转的 0 的最小数目。
示例 1:
输入:grid = [[0,1],[1,0]]
输出:1
示例 2:
输入:grid = [[0,1,0],[0,0,0],[0,0,1]]
输出:2
示例 3:
输入:grid = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
输出:1
思路:
最小翻转数 = 岛屿1 与 岛屿2 之间的最短路径
dfs(遍历二维数组) + bfs(找到最短路径)
如何找到最短路径?从一个岛屿开始,一圈一圈往外扩(BFS),直到扩展到第二座岛 。
遍历的思路类似于上题的最大人工岛,将遍历过的岛屿标记成“2”来做区分,而不是简单地淹掉。
- class Solution {
- public:
- int shortestBridge(vector
int >>& grid) { - vector
int>> dire={{1,0},{0,1},{-1,0},{0,-1}}; - queue
int,int>> q;//队列中装的是各点的坐标 - int n=grid.size();
- int count=1;
- for(int i=0;i
//只遍历一座岛屿,做队列的初始化 - {
- for(int j=0;j
- {
- if(grid[i][j]==1&&count>0)
- {
- dfs(grid,q,i,j);
- count--;
- }
- }
- }
- int step=0;
- while(!q.empty())
- {
- int size=q.size();
- for(int i=0;i
//让岛屿周围的一圈海都向外扩展 - {
- auto [x,y]=q.front();//用队头的pair赋给auto [x,y],就不需要用first和second
- q.pop();
- if(grid[x][y]==1)//最终结果的条件判断
- {
- return step;
- }
- for(int j=0;j
size();j++)//从一个点向四个方向扩散(做选择) - {
- int xn=x;
- int yn=y;
- xn+=dire[j][0];
- yn+=dire[j][1];
- if(xn<0||yn<0||xn>=n||yn>=n)
- {
- continue;
- }
- if(grid[xn][yn]==0)//将周围的一圈海标记为2
- {
- grid[xn][yn]=2;
- q.emplace(xn,yn);
- }
- if(grid[xn][yn]==1)//扩散中接触到了陆地,最短路径为step+1
- return step+1;
- }
- }
- step++;
- }
- return -1;
- }
- //深度优先遍历第一座岛,将岛屿及其周边的一圈都标记为 2
- //将岛屿周边的一圈海的位置(i,j)压入队列中,做队列的初始化
- void dfs(vector
int >>& grid,queueint ,int>>& q,int i,int j) - {
- int n=grid.size();
- if(i<0||j<0||i>=n||j>=n)
- {
- return ;
- }
- if(grid[i][j]==0)//岛屿周边的一圈海
- {
- grid[i][j]=2;//标记为 2
- q.emplace(i,j);//将其位置(i,j)压入队列中
- return ;
- }
- if(grid[i][j]==2)//遇到已经遍历过的,直接返回
- return ;
- grid[i][j]=2;//将遍历到的岛屿标记为 2
- dfs(grid,q,i+1,j);
- dfs(grid,q,i,j+1);
- dfs(grid,q,i-1,j);
- dfs(grid,q,i,j-1);
- }
- };
-
相关阅读:
HiEngine:可媲美本地的云原生内存数据库引擎
!力扣 108. 将有序数组转换为二叉搜索树
mqant启动流程
前端培训技术Less,Sass,Styus三者的区别
此文带你详细了解MySQL数据库的存储引擎知识
JAVA也能用上Seq啦
微信小程序 java精品课程在线学习平台
IPv6实现内网穿透,极低成本保姆级教程
windows cmd 常用操作命令
@Component 和 @Bean的区别
-
原文地址:https://blog.csdn.net/weixin_50437588/article/details/126801063