101.孤岛的总面积
文字讲解:101. 孤岛的总面积 | 代码随想录
解题思路
本题要求找到不靠边的陆地面积,那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然后再去重新遍历地图 统计此时还剩下的陆地就可以了。
在遇到地图周边陆地的时候,将1都变为0,此时地图为这样:
这里使用深搜
#include<bits/stdc++.h>
using namespace std;
int dir[4][2] = {0, 1, 1,0, 0,-1, -1,0};
int result =0 ; //用于后续记录结果
void dfs(vector<vector<int>>& grid , int x, int y)
{
grid[x][y] = 0;
result++;
int n = grid.size();
int m = grid[0].size();
for(int i=0 ; i<4 ; i++)
{
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
if(nextx<0 || nextx>= n || nexty < 0 ||nexty >= m) continue; //越界了
if(grid[nextx][nexty]==0) continue; //已经是海了
dfs(grid,nextx,nexty);
}
return;
}
int main()
{
int n,m;
cin >> n >> m;
vector<vector<int>> grid(n,vector<int>(m,0));
for(int i =0 ;i< n ; i++)
{
for(int j=0; j < m; j++)
{
cin>> grid[i][j];
}
}
//将地图左侧和右侧的陆地变海洋
for(int i = 0 ;i < n ; i++)
{
if(grid[i][0]==1) dfs(grid,i,0);
if(grid[i][m-1]==1) dfs(grid,i,m-1);
}
for(int j=0 ; j< m ; j++)
{
if(grid[0][j]==1) dfs(grid,0,j);
if(grid[n-1][j]==1) dfs(grid,n-1,j);
}
result = 0; //全变为海洋后,再去遍历剩余的孤岛
for(int i =0; i<n; i++)
{
for(int j =0 ;j < m; j++)
{
if(grid[i][j]==1) dfs(grid,i,j);
}
}
cout << result << endl;
}
102.沉没孤岛
文字讲解:102. 沉没孤岛 | 代码随想录
解题思路
步骤一:深搜或者广搜将地图周边的 1 (陆地)全部改成 2 (特殊标记)
步骤二:将水域中间 1 (陆地)全部改成 水域(0)
步骤三:将之前标记的 2 改为 1 (陆地)
这次我们使用广搜
#include<bits/stdc++.h>
using namespace std;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
void bfs(vector<vector<int>>& grid , int x, int y)
{
queue<pair<int,int>> que;
que.push({x,y});
grid[x][y]=2; //将连接的岛屿都变为2
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];
int n = grid.size();
int m = grid[0].size();
if(nextx<0 || nextx>= n || nexty <0 || nexty >=m ) continue;
if(grid[nextx][nexty]==0 || grid[nextx][nexty]==2) continue;
//如果下一个格子是海洋或者已经标记过的,就跳过
que.push({nextx,nexty});
grid[nextx][nexty] = 2;
}
}
}
int main()
{
int n,m;
cin >> n >> m;
vector<vector<int>> grid(n,vector<int>(m,0));
for(int i =0 ; i< n ; i++)
{
for(int j = 0 ; j< m ;j++)
{
cin>> grid[i][j];
}
}
for(int i =0 ; i< n; i++) //标记两侧
{
if(grid[i][0]==1) bfs(grid,i,0);
if(grid[i][m-1]==1) bfs(grid,i,m-1);
}
for(int j =0 ; j< m; j++) //标记上下
{
if(grid[0][j]==1) bfs(grid,0,j);
if(grid[n-1][j]==1) bfs(grid,n-1,j);
}
for(int i =0 ; i< n ; i++)
{
for(int j = 0 ; j< m ;j++)
{
if(grid[i][j]==1) grid[i][j] = 0; //变为海洋
if(grid[i][j]==2 ) grid[i][j] = 1;
}
}
for(int i =0 ; i< n ; i++)
{
for(int j = 0 ; j< m ;j++)
{
cout<< grid[i][j] << " ";
}
cout << endl;
}
}
103.水流问题
文字讲解:103. 水流问题 | 代码随想录
思路一:遍历每个点,去看是否能到达两个边界,但这样肯定超时,遍历每个节点是m*n的复杂度,而深搜每个节点又是m*n的复杂度
思路二:逆流优化
从第一组边界上的节点 逆流而上,将遍历过的节点都标记上。
同样从第二组边界的边上节点 逆流而上,将遍历过的节点也标记上。
然后两方都标记过的节点就是既可以流太平洋也可以流大西洋的节点。
这里使用深搜
#include<bits/stdc++.h>
using namespace std;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
void dfs(vector<vector<int>>& grid ,vector<vector<bool>>& visited , int x, int y)
{
if(visited[x][y])
return;
visited[x][y] = true;
for(int i = 0 ; i< 4 ;i++)
{
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
int n = grid.size();
int m = grid[0].size();
if(nextx<0 || nextx>= n || nexty<0 || nexty>=m) continue; //越界
if(grid[x][y] > grid[nextx][nexty]) continue; //我们这里是从低到高遍历
dfs(grid,visited,nextx,nexty);
}
return;
}
int main()
{
int n,m;
cin>>n>>m;
vector<vector<int>> grid(n,vector<int>(m,0));
vector<vector<bool>> firstBoard(n,vector<bool>(m,0));
vector<vector<bool>> secondBoard(n,vector<bool>(m,0));
for(int i =0 ;i< n; i++)
{
for(int j = 0; j<m ;j++)
{
cin>>grid[i][j];
}
}
for(int i =0 ; i < n ;i++)
{
dfs(grid,firstBoard,i,0);
dfs(grid,secondBoard,i,m-1);
}
for(int j=0 ; j<m ; j++)
{
dfs(grid,firstBoard,0,j);
dfs(grid,secondBoard,n-1,j);
}
for(int i =0 ;i< n; i++)
{
for(int j = 0; j<m ;j++)
{
if(firstBoard[i][j]&&secondBoard[i][j]) cout<< i << " " << j <<endl;
}
}
}
104.建造最大岛屿
文字讲解: 104.建造最大岛屿 | 代码随想录
解题思路
思路一:计算地图的最大面积:遍历地图 + 深搜岛屿,时间复杂度为 n * n。
每改变一个0的方格,都需要重新计算一个地图的最大面积,所以 整体时间复杂度为:n^4
思路二:
其实每次深搜遍历计算最大岛屿面积,我们都做了很多重复的工作。
只要用一次深搜把每个岛屿的面积记录下来就好。
第一步:一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map记录,key为岛屿编号,value为岛屿面积
第二步:再遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。
拿如下地图的岛屿情况来举例: (1为陆地)
第二步:再遍历地图,遍历每一个0的位置,求最大面积即可
时间复杂度:O(n^2)
#include<bits/stdc++.h>
using namespace std;
int n,m;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
int area = 0; //面积
void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y, int mark) {
if (visited[x][y] || grid[x][y] == 0) return; // 终止条件:访问过的节点 或者 遇到海水
visited[x][y] = true; // 标记访问过
grid[x][y] = mark; // 给陆地标记新标签
area++;
for (int i = 0; i < 4; i++) {
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
if (nextx < 0 || nextx >= n || nexty < 0 || nexty >= m) continue; // 越界了,直接跳过
dfs(grid, visited, nextx, nexty, mark);
}
}
int main()
{
cin >> n >> m;
vector<vector<int>> grid(n,vector<int>(m,0));
vector<vector<bool>> visited(n,vector<bool>(m,false));
for(int i=0 ;i < n ; i++)
{
for(int j=0; j < m ; j++)
{
cin>>grid[i][j];
}
}
int mask =2; //从2开始标记
unordered_map<int,int> map; //用来存面积
bool allGrid = true;
for(int i=0 ;i < n ; i++)
{
for(int j=0; j < m ; j++)
{
if(grid[i][j] == 0) allGrid = false;
if(!visited[i][j] && grid[i][j]==1) //遇到辛岛屿了
{
area = 0; //面积重置为0
dfs(grid,visited,i,j,mask);
map[ mask ] = area; //记录这个岛屿的面积
mask++;
}
}
}
if(allGrid)
{
cout << n * m <<endl;
return 0;
}
int result = 0;
unordered_set<int> visitedGrid;
for(int i=0 ;i < n ; i++)
{
for(int j=0; j < m ; j++)
{
area = 1; //变为1后的岛屿总面积
visitedGrid.clear(); //每次换格子变1时需要重置
if(grid[i][j]==0)
{
for (int k = 0; k < 4; k++) {
int neari = i + dir[k][1]; // 计算相邻坐标
int nearj = j + dir[k][0];
if (neari < 0 || neari >= n || nearj < 0 || nearj >= m) continue;
if (visitedGrid.count(grid[neari][nearj])) continue; // 添加过的岛屿不要重复添加
// 把相邻四面的岛屿数量加起来
area += map[grid[neari][nearj]];
visitedGrid.insert(grid[neari][nearj]); // 标记该岛屿已经添加过
}
}
result = max(result,area);
}
}
cout << result << endl;
}