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
    }
};
复制代码