代码随想录算法训练营
Day51 代码随想录算法训练营第 51 天 |LeetCode99岛屿数量 LeetCode100.岛屿的最大面积
目录
前言
LeetCode200 岛屿数量
LCR 105. 岛屿的最大面积
一、广度优先搜索基础
1、用队列实现
2、代码框架:
(1)起始节点加入队列
(2)只要加入队列,立刻标记为访问过的节点
(3)开始遍历队列里的元素
1)从队列取元素
2)开始想当前节点的四个方向左右上下去遍历
3)坐标越界了,直接跳过
4)如果节点没被访问过
① 队列添加该节点为下一轮要遍历的节点
② 只要加入队列立刻标记,避免重复访问
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 表示四个方向
// grid 是地图,也就是一个二维数组
// visited标记访问过的节点,不要重复访问
// x,y 表示开始搜索节点的下标
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
queue<pair<int, int>> que; // 定义队列
que.push({x, y}); // 起始节点加入队列
visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点
while(!que.empty()) { // 开始遍历队列里的元素
pair<int ,int> cur = que.front(); que.pop(); // 从队列取元素
int curx = cur.first;
int cury = cur.second; // 当前节点坐标
for (int i = 0; i < 4; i++) { // 开始想当前节点的四个方向左右上下去遍历
int nextx = curx + dir[i][0];
int nexty = cury + dir[i][1]; // 获取周边四个方向的坐标
if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 坐标越界了,直接跳过
if (!visited[nextx][nexty]) { // 如果节点没被访问过
que.push({nextx, nexty}); // 队列添加该节点为下一轮要遍历的节点
visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问
}
}
}
}
二、卡码网99岛屿数量(LeetCode200 岛屿数量 )
1.题目链接
2.思路
(1)深度优先搜索
1)思路:遍历所有点,遇到没有遍历过的陆地就是找到了新的岛屿,利用深度优先搜索将这个陆地点同一岛屿的所有陆地点都标记为已经搜索
2)深度优先搜索:
① 参数和返回值
参数:坐标,图数组,访问数组
② 终止条件:超出图边界,已经访问过,海洋
没有终止条件的写法:将终止条件写在递归调用前,不满足条件的不调用
③ 操作:
遍历上下左右,递归调用
(2)广度优先搜索
1)思路:遍历所有点,遇到没有遍历过的陆地就是找到了新的岛屿,利用广度优先搜索将这个陆地点同一岛屿的所有陆地点都标记为已经搜索
2)广度优先搜索:
① 参数和返回值
参数:坐标,图数组,访问数组
② 队列:
每次进行bfs先创建队列,把当前点放进去,标记visit
③ 遍历:
队列不空就不停止
每次遍历先求当前点坐标,将当前点弹出去
④ 操作:
- 遍历上下左右
- 每次检验点是否在范围内,且是没有visit过的陆地
- 点入队,visit标记
注意:每次点入队的时候进行visit标记
3.题解
(1)深度优先搜索
#include<bits/stdc++.h>
using namespace std;
int res=0;
int direction[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
void dfs(int x,int y,vector<vector<int>>&graph,vector<vector<int>>&visit)
{
if(x<=0 || y<=0||x>graph.size()||y>graph[0].size())return;
if(graph[x][y]==0||visit[x][y]==1)return;
visit[x][y]=1;
for(int i=0;i<4;i++)
{
int newx=x+direction[i][0];
int newy=y+direction[i][1];
if(newx<=0 || newy<=0||newx>graph.size()||newy>graph[0].size())continue;
dfs(newx,newy,graph,visit);
}
}
int main()
{
int n;
int m;
cin>>n>>m;
vector<vector<int>>graph(n+5,vector<int>(m+5,0));
vector<vector<int>>visit(n+5,vector<int>(m+5,0));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>graph[i][j];
}
}
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(graph[i][j]==1&&visit[i][j]==0)
{
res++;// 遇到没访问过的陆地--新的岛屿
//用深度优先搜索,将当前陆地相连的所有陆地记作visit=1
dfs(i,j,graph,visit);
}
}
}
cout<<res;
return 0;
}
(2)广度优先搜索
#include<bits/stdc++.h>
using namespace std;
int direction[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
void bfs(int x,int y,int n,int m,vector<vector<int>>&graph,vector<vector<int>>&visit)
{
queue<pair<int,int>>q;
q.push({x,y});
visit[x][y]=1;
while(!q.empty())
{
int curx=q.front().first ;
int cury=q.front().second;
q.pop();
for(int i=0;i<4;i++)
{
int newx=curx+direction[i][0];
int newy=cury+direction[i][1];
if(newx<=0 || newy<=0||newx>n||newy>m)
{
continue;
}
if(graph[newx][newy]==1 && visit[newx][newy]==0){
q.push({newx,newy});
visit[newx][newy]=1;
}
}
}
}
int main()
{
int n;
int m;
cin>>n>>m;
vector<vector<int>>graph(n+5,vector<int>(m+5,0));
vector<vector<int>>visit(n+5,vector<int>(m+5,0));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>graph[i][j];
}
}
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(graph[i][j]==1&&visit[i][j]==0)
{
res++;// 遇到没访问过的陆地--新的岛屿
//用深度优先搜索,将当前陆地相连的所有陆地记作visit=1
bfs(i,j,n,m,graph,visit);
}
}
}
cout<<res;
return 0;
}
三、LCR 105. 岛屿的最大面积
1.题目链接
2.思路
总体思路:遍历所有点,遇到没有遍历过的陆地就是找到了新的岛屿,利用深度优先搜索将这个陆地点同一岛屿的所有陆地点都标记为已经搜索,求岛屿的面积
(1)方法1:dfs处理当前点的上下左右的visit
1) 遍历点
如果点是陆地并且没有visit,那么:
① 岛屿面积重置为1(当前点在此处进行处理)
② 当前点标记visit
③ 深度优先搜索
④ res=max(res,s)
2)深度优先搜索
①参数和返回值
参数:坐标,图数组,访问数组
② 终止条件:将终止条件写在递归调用前,不满足条件的不调用,也不进行visit和面积处理
③ 操作:
遍历上下左右
跳过超出图范围的
是陆地并且没有visit的点:
- 标记visit,岛屿面积+1
- 递归调用
(2)方法1:dfs处理当前点的上下左右的visit
1) 遍历点
如果点是陆地并且没有visit,那么:
① 岛屿面积重置为0(当前点在dfs进行处理)
② 深度优先搜索
③ res=max(res,s)
2)深度优先搜索
①参数和返回值
参数:坐标,图数组,访问数组
② 终止条件:如果点是visit过的,或者是海洋,跳过
③ 操作:
当前点标记visit,岛屿面积+1
遍历上下左右
跳过超出图范围的
递归调用
3.题解
方法一:每次处理与当前点直接相连的点的visit和面积
#include<bits/stdc++.h>
using namespace std;
int s;
int direction[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
void dfs(int x,int y,vector<vector<int>>&graph,vector<vector<bool>>&visit)
{
for(int i=0;i<4;i++)
{
int nextx=x+direction[i][0];
int nexty=y+direction[i][1];
if(nexty<0||nextx<0||nexty>=graph[0].size()||nextx>=graph.size())
{
continue;
}
if(graph[nextx][nexty]==1 && visit[nextx][nexty]==0)
{
visit[nextx][nexty]=1;
s++;
dfs(nextx,nexty,graph,visit);
}
}
}
int main()
{
int n;
int m;
int res=0;
cin>>n>>m;
vector<vector<int>>graph(n,vector<int>(m,0));
vector<vector<bool>>visit(n,vector<bool>(m,false));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>graph[i][j];
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(graph[i][j]==1&&visit[i][j]==false)//提前检验,起到剪枝作用
{
s=1;//当前点算一个(重置面积)
visit[i][j]=1;
dfs(i,j,graph,visit);
res=max(res,s);
}
}
}
cout<<res;
return 0;
}
方法2:每次处理当前点的visit和面积
#include<iostream>
#include<vector>
using namespace std;
int s;
int direction[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
void dfs(int x,int y,vector<vector<int>>&graph,vector<vector<int>>&visit)
{
if(graph[x][y]==0||visit[x][y]==1)return;
visit[x][y]=1;
s++;
for(int i=0;i<4;i++)
{
int nextx=x+direction[i][0];
int nexty=y+direction[i][1];
if(nexty<0||nextx<0||nexty>=graph[0].size()||nextx>=graph.size())
{
continue;
}
dfs(nextx,nexty,graph,visit);
}
}
int main()
{
int n;
int m;
int res=0;
cin>>n>>m;
vector<vector<int>>graph(n,vector<int>(m,0));
vector<vector<int>>visit(n,vector<int>(m,0));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>graph[i][j];
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(graph[i][j]==1&&visit[i][j]==0)//提前检验,起到剪枝作用
{
s=0;//当前点算一个(重置面积)
dfs(i,j,graph,visit);
res=max(res,s);
}
}
}
cout<<res;
return 0;
}