题目
解题思路
本题可以使用DFS
解决。
遍历每个格子,如果该格子是陆地,就DFS
该陆地所在的岛屿,并计算岛屿面积,并修改格子值为2
防止重复遍历。在遍历过程中,只要有一块陆地在边界,这个岛屿就不是飞地,否则就是飞地。计算所有飞地面积之和,返回答案ans
。
dfs
遍历求所有岛屿面积参考LC200.岛屿数量
class Solution {
private:
constexpr static int direction[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};//方向辅助数组
public:
int numIslands(vector<vector<char>>& grid) {
int m = grid.size(), n = grid[0].size();//计算网格长宽
function<void(int,int)> func = [&](int x, int y){//dfs
grid[x][y] = '2';//修改值为2防止重复遍历
for(const auto& [xOfs,yOfs] : direction){//对四个方向上是陆地的地方dfs
int i = x + xOfs, j = y + yOfs;
if(i>=0 && j>=0 && i<m && j<n && grid[i][j]=='1') func(i,j);
}
};
int ans = 0;//存答案
for(int k = 0; k < m; ++k){//遍历网格
for(int z = 0; z < n; ++z){
if(grid[k][z]=='1'){//遇到陆地岛屿数量就加一
++ans;
func(k,z);//同时标记该岛屿所有陆地,防止重复遍历
}
}
}
return ans;//返回答案
}
};
class Solution {
private:
constexpr static int direction[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };//方向辅助数组
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();//计算网格长宽
int ans = 0, area = 0;//存答案,记录岛屿当前面积
function<void(int, int)> func = [&](int x, int y) {//dfs
grid[x][y] = 2;//每遍历一个陆地格子,将其值改为2防止重复遍历
++area;//当前岛屿面积加一
for (const auto& [xOfs, yOfs] : direction) {//依次遍历四个方向上是陆地的格子
int i = x + xOfs, j = y + yOfs;
if (i >= 0 && j >= 0 && i < m && j < n && grid[i][j] == 1) func(i, j);
}
};
for (int k = 0; k < m; ++k) {//依次遍历每个格子
for (int z = 0; z < n; ++z) {
if (grid[k][z] == 1) {//如果是陆地计算该陆地所在岛屿面积并标记
area = 0;
func(k, z);
if (area > ans) ans = area;//更新最大岛屿面积
}
}
}
return ans;//返回答案
}
};
class Solution {
constexpr static int direction[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };
public:
int largestIsland(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();//计算网格长宽
int ans = 0, area = 0;//存答案,记录各岛面积
vector<pair<int, int>> areas;//存所有岛及其面积
int count = 2;//岛屿标记
//dfs函数
function<void(int, int)> func = [&](int x, int y) {//dfs求岛屿面积
grid[x][y] = count;//标记陆地的岛屿号
++area;//每遍历一块陆地,岛屿面积加一
for (const auto& [xOfs, yOfs] : direction) {//依次从四个方向进行dfs
int i = x + xOfs, j = y + yOfs;
if (i >= 0 && j >= 0 && i < m && j < n && grid[i][j] == 1) func(i, j);
}
};
bool isThereAWaterArea = false;//判断有没有水
for (int k = 0; k < m; ++k) {
for (int z = 0; z < n; ++z) {
if (grid[k][z] == 1) {
area = 0;//初始化岛屿当前面积为0
func(k, z);//计算岛屿面积并进行陆地格子标记
areas.emplace_back(make_pair(count++, area));//将每个岛屿的标记-面积键值对压入数组
}
else if (grid[k][z] == 0) isThereAWaterArea = true;//有水则isThereAWaterArea = true
}
}
if (!isThereAWaterArea) return m * n;//没水直接返回网格总面积
if (areas.size() == 0) return 1;//没岛直接返回1
if (areas.size() == 1) return ++area;//只有一个岛直接返回该岛面积加一
for (int k = 0; k < m; ++k) {//依次遍历每个水域格子
for (int z = 0; z < n; ++z) {
if (grid[k][z] == 0) {
set<pair<int, int>> areasAround;//存储水域周边岛屿标记-面积键值对
//依次存入四周的岛屿
if (k > 0 && grid[k - 1][z] != 0) areasAround.emplace(areas[grid[k - 1][z] - 2]);
if (k < m - 1 && grid[k + 1][z] != 0) areasAround.emplace(areas[grid[k + 1][z] - 2]);
if (z > 0 && grid[k][z - 1] != 0) areasAround.emplace(areas[grid[k][z - 1] - 2]);
if (z < n - 1 && grid[k][z + 1] != 0) areasAround.emplace(areas[grid[k][z + 1] - 2]);
int areaTemp = 0;//四周岛屿面积总和,初始化为0
for (const auto& s : areasAround) areaTemp += s.second;
ans = ans < areaTemp ? areaTemp : ans;//更新最大人工岛面积
}
}
}
return ++ans;//返回答案,++是加上被填为陆地的水域格子
}
};
代码
class Solution {
private:
constexpr static int direction[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };//方向辅助数组
public:
int numEnclaves(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();//计算网格长宽
int ans = 0, area = 0;//存答案,记录岛屿当前面积
//dfs函数
function<bool(int, int)> func = [&](int x, int y) {//dfs
bool isAnEnclaves;
if(x==0 || x==m-1 || y==0 || y==n-1) isAnEnclaves = false;//如果在边界,该陆地不是飞地
else isAnEnclaves = true;
grid[x][y] = 2;//每遍历一个陆地格子,将其值改为2防止重复遍历
++area;//当前岛屿面积加一
for (const auto& [xOfs, yOfs] : direction) {//依次遍历四个方向上是陆地的格子
int i = x + xOfs, j = y + yOfs;
if (i >= 0 && j >= 0 && i < m && j < n && grid[i][j] == 1){
if(!func(i, j)) isAnEnclaves = false;//只要岛屿中有一块陆地不是飞地,则整个岛屿都不是飞地
}
}
return isAnEnclaves;
};
for (int k = 0; k < m; ++k) {//依次遍历每个格子
for (int z = 0; z < n; ++z) {
if (grid[k][z] == 1) {//如果是陆地计算该陆地所在岛屿面积并标记
area = 0;
if(func(k, z)) ans += area;//累加飞地面积
}
}
}
return ans;//返回答案
}
};
复杂度分析
时间复杂度: O(mn)
。m
,n
分别为网格长宽,需要遍历每个格子一次。
空间复杂度: O(log(max(m,n))
。递归栈的空间消耗。