链接:https://leetcode.cn/problems/making-a-large-island
给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。返回执行此操作后,grid 中最大的岛屿面积是多少?岛屿 由一组上、下、左、右四个方向相连的 1 形成。
输入: grid = [[1, 0], [0, 1]]
输出: 3
解释: 将一格0变成1,最终连通两个小岛得到面积为 3 的岛屿。
输入: grid = [[1, 1], [1, 0]]
输出: 4
解释: 将一格0变成1,岛屿的面积扩大为 4。
输入: grid = [[1, 1], [1, 1]]
输出: 4
解释: 没有0可以让我们变成1,面积依然为 4。
n == grid.length
n == grid[i].length
1 <= n <= 500
grid[i][j] 为 0 或 1
看到图中岛屿,即相连的点关系,就想到了dfs求岛屿
由于n <= 500, 所以n2的复杂度可以接受,dfs的大小无非是(500*500)2,可以接受
解题思路:
class Solution {
public:
void dfs(int i, int j, int flag, vector<vector<int>>& grid){
// 深度遍历,对上下左右四个点递归,若是1,则加入岛屿,并面积++
if(!grid[i][j] or mark[i][j]) return;
mark[i][j] = 1; // 已处理
int n = grid.size();
mp1[pair(i,j)] = flag;
mp2[flag]++;
for(int k = 0; k < 4; k++){
int x = i+dx[k],y = j+dy[k];
if(x < 0 or x >= n or y < 0 or y >= n) continue;
dfs(x, y, flag, grid);
}
return;
}
int largestIsland(vector<vector<int>>& grid) {
int n = grid.size();
// 首先将格子内的岛屿归类,用map存储每个1的格子对应的岛屿编号
int flag = 1;
for(int i = 0 ;i < n; i++){
for(int j = 0; j < n; j++){
if(!mp1.count(pair(i,j)) and grid[i][j]){
// 该格子为1且没被任何岛屿归类
mp2[flag] = 0;
dfs(i, j, flag++, grid);
}
}
}
// 遍历所有的点,翻转尝试
int ans = 0;
for(int i = 0 ;i < n; i++){
for(int j = 0; j < n; j++){
// 将点ij变成1,包含此点本身就是1
set<int> s; // 上下左右的岛屿编号集合
if(grid[i][j]) s.insert(mp1[pair(i,j)]); // 当前的点为1,先将其所在岛屿加入集合,防止其为孤岛(面积为1),下面计算周围岛屿未算上本身岛屿
// 将周边岛屿编号加入集合
for(int k = 0; k < 4; k++){
int x = i+dx[k],y = j+dy[k];
if(mp1[pair(x,y)]) s.insert(mp1[pair(x,y)]); // 将岛屿编号加入集合
}
// 遍历集合中岛屿计算结果
int cnt = 0;
for(auto item = s.begin(); item != s.end(); item++){
cnt += mp2[*item];
}
if(grid[i][j]) ans = max(cnt, ans); // 该点本来就是1,所有岛屿的面积和
else ans = max(cnt+1, ans); // 该点变为1,隔壁岛屿的面积加上他
}
}
return ans;
}
private:
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0 , -1, 0};
map<pair<int, int>, int> mp1; // 每个点映射到岛屿编号
map<int, int> mp2; // 每个岛屿编号映射到面积
int mark[510][510] = {0};
};