827. 最大人工岛
困难
相关标签
深度优先搜索 广度优先搜索 并查集 数组 矩阵
给你一个大小为 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。
提示:
n == grid.length
n == grid[i].length
1 <= n <= 500
grid[i][j]
为 0
或 1
首先我们定义了一个私有变量
count
和一个二维数组dir
,用于表示四个方向的移动。接着有一个私有函数dfs
,用于深度优先搜索并标记相邻的陆地块。在公共部分,我们有一个公共函数
largestIsland
,它首先初始化一些变量,然后通过 DFS 标记每个岛屿,并记录每个岛屿的面积。接着,对于每个海洋块,计算连接的岛屿面积之和,并找出最大值作为结果。整体逻辑可以分为以下几个步骤:
- 初始化:定义变量和数据结构,包括记录岛屿面积的变量、四个方向的数组、以及标记是否整个地图都是陆地的变量。
- 深度优先搜索和标记:遍历地图,对于每个未访问过的陆地块,使用深度优先搜索标记与其相邻的陆地块,并记录每个岛屿的面积。
- 计算连接的岛屿面积之和:遍历海洋块,计算连接的岛屿面积之和,并找出最大值作为结果。
在第三步中,对于每个海洋块,我们会判断其周围相邻的岛屿,并计算连接的岛屿面积之和。最后找出最大值作为结果返回。
因此,整体的时间复杂度为 O(n*m),其中 n 为网格的行数,m 为网格的列数。
因此,整体的空间复杂度为 O(n*m),其中 n 为网格的行数,m 为网格的列数。
// 计算给定二维网格中最大的岛屿面积
class Solution {
private:
int count; // 用于记录岛屿面积
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
// 深度优先搜索标记相邻的陆地块
void dfs(vector>& grid, vector>& visited, int x, int y, int mark) {
if (visited[x][y] || grid[x][y] == 0) return; // 终止条件:访问过的节点 或者 遇到海水
visited[x][y] = true; // 标记访问过
grid[x][y] = mark; // 给陆地标记新标签
count++; // 岛屿面积加一
for (int i = 0; i < 4; i++) {
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过
dfs(grid, visited, nextx, nexty, mark);
}
}
public:
// 计算最大岛屿面积
int largestIsland(vector>& grid) {
int n = grid.size(), m = grid[0].size();
vector> visited = vector>(n, vector(m, false)); // 标记访问过的点
unordered_map gridNum; // 存储每个岛屿的面积
int mark = 2; // 记录每个岛屿的编号
bool isAllGrid = true; // 标记是否整个地图都是陆地
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 0) isAllGrid = false;
if (!visited[i][j] && grid[i][j] == 1) {
count = 0;
dfs(grid, visited, i, j, mark); // 将与其链接的陆地都标记上 true
gridNum[mark] = count; // 记录每一个岛屿的面积
mark++; // 记录下一个岛屿编号
}
}
}
if (isAllGrid) return n * m; // 如果都是陆地,返回全面积
// 以下逻辑是根据添加陆地的位置,计算周边岛屿面积之和
int result = 0; // 记录最后结果
unordered_set visitedGrid; // 标记访问过的岛屿
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int count = 1; // 记录连接之后的岛屿数量
visitedGrid.clear(); // 每次使用时,清空
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 >= grid.size() || nearj < 0 || nearj >= grid[0].size()) continue;
if (visitedGrid.count(grid[neari][nearj])) continue; // 添加过的岛屿不要重复添加
// 把相邻四面的岛屿数量加起来
count += gridNum[grid[neari][nearj]];
visitedGrid.insert(grid[neari][nearj]); // 标记该岛屿已经添加过
}
}
result = max(result, count);
}
}
return result;
}
};
class Solution {
private static final int[][] position = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 四个方向
/**
* @param grid 矩阵数组
* @param row 当前遍历的节点的行号
* @param col 当前遍历的节点的列号
* @param mark 当前区域的标记
* @return 返回当前区域内 1 的数量
*/
public int dfs(int[][] grid, int row, int col, int mark) {
int ans = 0;
grid[row][col] = mark; // 将当前位置标记为指定标记
for (int[] current: position) {
int curRow = row + current[0], curCol = col + current[1];
if (curRow < 0 || curRow >= grid.length || curCol < 0 || curCol >= grid.length) continue; // 越界检查
if (grid[curRow][curCol] == 1)
ans += 1 + dfs(grid, curRow, curCol, mark); // 统计当前区域内 1 的数量
}
return ans;
}
public int largestIsland(int[][] grid) {
int ans = Integer.MIN_VALUE, size = grid.length, mark = 2; // 初始化变量
Map getSize = new HashMap<>(); // 用于存储每个岛屿区域的大小
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
if (grid[row][col] == 1) {
int areaSize = 1 + dfs(grid, row, col, mark); // 计算当前岛屿区域的大小
getSize.put(mark++, areaSize); // 将岛屿区域的大小存入map中
}
}
}
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
if (grid[row][col] != 0) continue; // 如果当前位置不是 0,则跳过
Set hashSet = new HashSet<>(); // 用于防止重复计算同一区域
int curSize = 1; // 初始化当前区域的大小为 1
for (int[] current: position) {
int curRow = row + current[0], curCol = col + current[1];
if (curRow < 0 || curRow >= grid.length || curCol < 0 || curCol >= grid.length) continue;
int curMark = grid[curRow][curCol]; // 获取对应位置的标记
if (hashSet.contains(curMark) || !getSize.containsKey(curMark)) continue; // 检查是否已经处理过该区域
hashSet.add(curMark);
curSize += getSize.get(curMark); // 更新当前区域的大小
}
ans = Math.max(ans, curSize); // 更新最大岛屿大小
}
}
// 当 ans == Integer.MIN_VALUE 说明矩阵数组中不存在 0,全都是有效区域,返回数组大小即可
return ans == Integer.MIN_VALUE ? size * size : ans;
}
}
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。