827. 最大人工岛
难度
困难
269
给你一个大小为 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
思路:
基本思路比较好想 对于任意一个为0的格子
我们考虑将其变为1后的联通面积
那么如何计算将其变为1后的联通面积呢?
一个思路是将其上下左右元素的联通面积加起来加一就是将该元素变为1后的联通面积
此时我们需要注意的是有可能其上下左右任意多个本来就是联通的,此时我们不能多次重复计算
所以需要对连通区域编号,当我们遍历到一个为0的格子,我们分别向上下左右dfs寻找其对应的联通面积,那么也就是说我们需要记录该连通区域已经访问过的格子,当我们下一次访问该格子时,不需要重新向四个方向遍历,只需要查询已有的连通区域编号
AC代码
class Solution { public: vector<int> regions; int largestIsland(vector<vector<int>>& grid) { //对于矩阵中的零元素 求将其从0变为1后的联通的岛屿面积 //vector<vector<int>> link(n,vector<int>(n,0)); int res = 0; int n = grid.size(); visited = vector<vector<int>>(n, vector<int>(n, -1)); //思考如何降低复杂度 例如联通的不进行重复计算 如果某一条通路已经被计算过了 for (int i = 0; i < grid.size(); i++) { for (int j = 0; j < grid[0].size(); j++) { //dfs if (!grid[i][j]) { //分别找上下左右的连通区域 set<int> link; int temp = 1; if (i - 1 >= 0) { //存在上邻居 寻找上邻居的连通区域 if (grid[i - 1][j] == 1) { regions.push_back(0); dfs(i - 1, j, grid, regions.size()); } if (grid[i - 1][j] < 0) link.insert(-grid[i - 1][j] - 1); } if (i + 1 < n) { if (grid[i + 1][j] == 1) { regions.push_back(0); dfs(i + 1, j, grid, regions.size()); } if (grid[i + 1][j] < 0) link.insert(-grid[i + 1][j] - 1); } if (j - 1 >= 0) { if (grid[i][j - 1] == 1) { regions.push_back(0); dfs(i, j - 1, grid, regions.size()); } if (grid[i][j - 1] < 0) link.insert(-grid[i][j - 1] - 1); } if (j + 1 < n) { if (grid[i][j + 1] == 1) { regions.push_back(0); dfs(i, j + 1, grid, regions.size()); } if (grid[i][j + 1] < 0) link.insert(-grid[i][j + 1] - 1); } for (auto& i : link) { temp += regions[i]; } res = max(res, temp); } } } return res == 0 ? n * n : res; } void dfs(int i, int j, vector<vector<int>>& grid, int region) { //遍历每个格子的上下左右寻找与其相连的连通区域的最大面积 if (i < 0 || j < 0 || i == grid.size() || j == grid.size()) return;//边界判断 if (grid[i][j] == 1) { //如何标记已经遍历过了的点 //属于同一连通区域 grid[i][j] = -region; regions[region - 1]++;//该连通区域的元素数量加一 dfs(i, j - 1, grid, region); dfs(i, j + 1, grid, region); dfs(i - 1, j, grid, region); dfs(i + 1, j, grid, region); } //区域为0 //单独的dfs会导致重复的联通区域被计算 //向四个方向分别dfs dfs过程中标记 //该区域已经被遍历过了 直接返回0 } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理