827. 最大人工岛

链接:https://leetcode.cn/problems/making-a-large-island

给你一个大小为 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

题解 DFS & 归类

看到图中岛屿,即相连的点关系,就想到了dfs求岛屿

由于n <= 500, 所以n2的复杂度可以接受,dfs的大小无非是(500*500)2,可以接受
解题思路

  • 分类: 将所有岛屿编号,记录岛屿信息(点,面积),可以用map来映射 每个点映射到岛屿编号,每个岛屿编号映射到面积;
  • DFS: 分类的时候通过DFS遍历,从一个点出发找到该点所在岛屿所有点,并记录岛屿信息(点,面积);(注意DFS中防止陷入循环用mark记录已经遍历过的点)
  • 翻转点求面积
    • 当前点为1,则无需翻转,面积=当前点所在岛屿加周边四个方向的岛屿面积
    • 当前点为0,翻转,面积 = 1 + 周边四个方向的岛屿面积
  • 遍历每个点尝试翻转or不翻转求得临时面积,找到最大的那一个

代码

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};
};

你可能感兴趣的:(刷题,leetcode,算法,职场和发展)