• (图论) 827. 最大人工岛 ——【Leetcode每日一题】


    ❓ 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]01

    💡思路:

    本题的一个暴力想法,应该是遍历地图尝试 将每一个 0 改成1,然后去搜索地图中的最大的岛屿面积。

    本题使用 深搜 还是 广搜 都是可以的,其目的就是遍历岛屿做一个标记,相当于染色,那么使用哪个遍历方式都行,我用的是深搜

    根据暴力的想法每次深搜遍历计算最大岛屿面积,我们都做了很多重复的工作。只要用一次深搜把每个岛屿的面积记录下来就好。

    1. 一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map 记录,key 为岛屿编号,value 为岛屿面积,我是直接在原 grid 上直接标记;
    2. 在遍历地图,遍历 0 的方格(因为要将 0 变成 1),并统计该1(由 0 变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。

    🍁代码:(C++、Java)

    C++

    class Solution {
    private:
        int cnt;
        int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
        void dfs(vector<vector<int>>& grid, int x, int y, int mark){
            if(grid[x][y] == 0 || grid[x][y] != 1) return; // 遇到海水或访问过的节点,则终止
            grid[x][y] = mark; //给陆地标记新的标签
            cnt++;
            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, nextx, nexty, mark);
            }
        }
    public:
        int largestIsland(vector<vector<int>>& grid) {
            int m = grid.size(), n = grid[0].size();
            unordered_map<int, int> gridNum;
            int mark = 2;
            bool isAllGrid = true; // 标记是否整个地图都是陆地
            for(int i = 0; i < m; i++){
                for(int j = 0; j < n; j++){
                    if(grid[i][j] == 0) isAllGrid = false;
                    if(grid[i][j] == 1){
                        cnt = 0;
                        dfs(grid, i, j, mark);
                        gridNum[mark] = cnt;
                        mark++;
                    }
                }
            }
            if (isAllGrid) return n * m; // 如果都是陆地,返回全面积
    
            // 以下逻辑是根据添加陆地的位置,计算周边岛屿面积之和
            int ans = 0;
            unordered_set<int> visitedGrid;  // 标记访问过的岛屿
            for(int i = 0; i < m; i++){
                for(int j = 0; j < n; j++){
                    int num = 1;
                    visitedGrid.clear(); // 每次使用时,清空
                    if(grid[i][j] == 0){
                        for(int k = 0; k < 4; k++){
                            int neari = i + dir[k][0];
                            int nearj = j + dir[k][1];
                            if (neari < 0 || neari >= grid.size() || nearj < 0 || nearj >= grid[0].size()) continue;
                            if (visitedGrid.count(grid[neari][nearj])) continue;
                             // 把相邻四面的岛屿数量加起来
                            num += gridNum[grid[neari][nearj]];
                            visitedGrid.insert(grid[neari][nearj]); // 标记该岛屿已经添加
                        }
                    }
                    ans = max(ans, num);
                }
            }
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    Java

    class Solution {
        private static final int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 四个方向
        private int cnt;
        private void dfs(int[][] grid, int x, int y, int mark){
            if(grid[x][y] != 1) return;
            grid[x][y] = mark;
            cnt++;
            for(int i = 0; i < 4; i++){
                int nextx = x + dir[i][0];
                int nexty = y + dir[i][1];
                if(nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) continue;
                dfs(grid, nextx, nexty, mark);
            }
        }
        public int largestIsland(int[][] grid) {
            int m = grid.length, n = grid[0].length;
            Map<Integer, Integer> gridNum = new HashMap<>();
            int mark = 2;
            boolean isAllGrid = true;
            for(int i = 0; i < m; i++){
                for(int j = 0; j < n; j++){
                    if(grid[i][j] == 0) isAllGrid = false;
                    if(grid[i][j] == 1){
                        cnt = 0;
                        dfs(grid, i, j, mark);
                        gridNum.put(mark++, cnt);
                    }
                }
            }
            if(isAllGrid) return n * m;
    
            int ans = 0;
            for(int i = 0; i < m; i++){
                for(int j = 0; j < n; j++){
                    Set<Integer> hashSet = new HashSet<>();     // 防止同一个区域被重复计算
                    int num = 1;
                    if(grid[i][j] == 0){
                        for(int k = 0; k < 4; k++){
                            int neari = i + dir[k][0];
                            int nearj = j + dir[k][1];
                            if(neari < 0 || neari >= grid.length || nearj < 0 || nearj >= grid[0].length) continue;
                            int curMark = grid[neari][nearj];     // 获取对应位置的标记
                            if (hashSet.contains(curMark) || !gridNum.containsKey(curMark)) continue;
                            num += gridNum.get(curMark);
                            hashSet.add(curMark);
    
                        }
                        ans = Math.max(ans, num);
                    }
                }
            }
            return ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    🚀 运行结果:

    在这里插入图片描述

    🕔 复杂度分析:
    • 时间复杂度 O ( m n ) O(mn) O(mn),其中 mngrid的高和宽。方格地图中,每个节点我们就遍历一次,并不会重复遍历。
    • 空间复杂度 O ( m n ) O(mn) O(mn)

    题目来源:力扣。

    放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
    关注我LeetCode主页 / CSDN—力扣专栏,每日更新!

    注: 如有不足,欢迎指正!
  • 相关阅读:
    LinkedIn DataHub --- 经验分享
    Windows下,用python代码编译打包成可执行文件,并设置自启动步骤
    python多线程获取返回值
    c:Bubble Sort
    论文精读:DEFORMABLE DETR: DEFORMABLE TRANSFORMERSFOR END-TO-END OBJECT DETECTION
    Vue2中$set的使用
    为啥https比http慢
    【网络】五中IO模型介绍 + 多路转接中select和poll服务器的简单编写
    5. 多重背包问题 II(acwing)
    Android am start命令
  • 原文地址:https://blog.csdn.net/weixin_43412762/article/details/132772944