首页 > 其他分享 >图解LeetCode——827. 最大人工岛(难度:困难)

图解LeetCode——827. 最大人工岛(难度:困难)

时间:2023-05-23 11:01:12浏览次数:30  
标签:遍历 column 岛屿 int grid 人工岛 827 LeetCode row

给你一个大小为 n x n 二进制矩阵 grid最多 只能将一格 0 变成 1

返回执行此操作后,grid 中最大的岛屿面积是多少?

岛屿 由一组四个方向相连的 1 形成。

二、示例

2.1> 示例 1:

【输入】 grid = [[1, 0], [0, 1]]
【输出】 3
【解释】 将一格0变成1,最终连通两个小岛得到面积为 3 的岛屿。

2.2> 示例 2:

【输入】 grid = [[1, 1], [1, 0]]
【输出】 4
【解释】 将一格0变成1,岛屿的面积扩大为 4。

2.3> 示例 3:

【输入】 grid = [[1, 1], [1, 1]]
【输出】 4
【解释】 没有0可以让我们变成1,面积依然为 4。

提示:

  • n == grid.length
  • n == grid[i].length
  • 1 <= n <= 500
  • grid[i][j] 为 01

三、解题思路

根据题意,我们可以知道整个“矩阵地图”中,是由岛屿(格子值为:1)和海洋(格子值为:0)组成的。那么,题目要求计算“经过某些操作”之后的岛屿面积,而岛屿是不同的,所以我们可以在遍历整个矩阵的过程中,对不同的岛屿进行编号。由于0和1已经被使用了,那么岛屿的编号我们就从2开始,当遍历到新的岛屿编号加1。如下图所示,我们遍历出来了编号为2~8的岛屿。并且,在遍历过程中,将每个岛屿的面积也统计出来,并保存到Map中(key=岛屿编号value=岛屿面积)。如下图所示:

图解LeetCode——827. 最大人工岛(难度:困难)_后端

那么,下一步就需要根据题意的要求——即:“最多只能将一格0变为1”。那么我们遍历矩阵中的所有格子,只有当格子是海洋(格子值为:0)时,我们来判断其上、下、左、右格子的值,再来结合Map中存储的岛屿编号与面积的对应关系,进行岛屿面积计算即可。以下图为例,在我们遍历的这个格子周围:上格子值为:2,下格子值为:6,左格子为:0,右格子为:0,所以我们可以知道这块海洋格子与岛屿2和岛屿6是相邻的,那么总的面积就是:岛屿2面积(10)+ 岛屿6面积(4)+ 海洋格子翻转面积(1)= 15。通过这种方式,将遍历所有格子后,最大的岛屿面积作为方法返回值即可。

图解LeetCode——827. 最大人工岛(难度:困难)_后端_02

这里再补充说一下,对于每个格子遍历的时候,我们采用深度优先遍历方式,即:先后深度的去遍历该格子的上方向、下方向、左方向和右方向。

图解LeetCode——827. 最大人工岛(难度:困难)_后端_03

为了防止遍历不同格子时,出现重复遍历,我们采取遍历到“岛屿”后,将格子值赋值为岛屿编号的方式。那么,终止深度遍历的条件如下所示:

条件一:遍历格子下标已经越界,即:不满足 row >=0 && row < grid.length && column >= 0 && column < grid.length条件二:遍历的格子不为1。即:不遍历海洋格子和已遍历编号过的岛屿。

四、代码实现

class Solution {
    public int largestIsland(int[][] grid) {
        if (grid == null || grid.length == 0) return 1;
        int result = 0, index = 2;
        HashMap<Integer, Integer> areasMap = new HashMap();
        for (int i = 0; i < grid.length; i++)
            for (int j = 0; j < grid[0].length; j++)
                if (grid[i][j] == 1) areasMap.put(index, calculateAreas(index++, grid, i, j)); // 只计算未编号的岛屿

        if (areasMap.size() == 0) return 1; // 没有岛屿,全是海洋
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 0) {
                    Set<Integer> islands = getIslands(grid, i, j);
                    if (islands.size() == 0) continue; // 周围没有岛屿
                    result = Math.max(result, islands.stream().map(item -> areasMap.get(item)).reduce(Integer::sum).orElse(0) + 1);
                }
            }
        }
        if (result == 0) return areasMap.get(2); // 全是岛屿,没有海洋
        return result;
    }

    public int calculateAreas(int index, int[][] grid, int row, int column) {
        if (!isLegal(grid, row, column) || grid[row][column] != 1) return 0;
        grid[row][column] = index;
        return calculateAreas(index, grid, row + 1, column) + calculateAreas(index, grid, row - 1, column) + calculateAreas(index, grid, row, column - 1) + calculateAreas(index, grid, row, column + 1) + 1;
    }

    public boolean isLegal(int[][] grid, int row, int column) {
        return row >= 0 && row < grid.length && column >= 0 && column < grid[0].length;
    }

    public Set<Integer> getIslands(int[][] grid, int row, int column) {
        Set<Integer> result = new HashSet<>();
        if (isLegal(grid, row + 1, column) && grid[row + 1][column] != 0)
            result.add(grid[row + 1][column]);
        if (isLegal(grid, row - 1, column) && grid[row - 1][column] != 0)
            result.add(grid[row - 1][column]);
        if (isLegal(grid, row, column - 1) && grid[row][column - 1] != 0)
            result.add(grid[row][column - 1]);
        if (isLegal(grid, row, column + 1) && grid[row][column + 1] != 0)
            result.add(grid[row][column + 1]);
        return result;
    }
}

图解LeetCode——827. 最大人工岛(难度:困难)_算法_04

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

标签:遍历,column,岛屿,int,grid,人工岛,827,LeetCode,row
From: https://blog.51cto.com/u_15003301/6330131

相关文章

  • 图解LeetCode——904. 水果成篮(难度:中等)
    一、题目你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组fruits表示,其中fruits[i]是第i棵树上的水果种类。你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:你只有两个篮子,并且每个篮子只能装单一类型的水果......
  • #yyds干货盘点# LeetCode程序员面试金典:平衡二叉树
    题目:给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 示例1:输入:root=[3,9,20,null,null,15,7]输出:true示例2:输入:root=[1,2,2,3,3,null,null,4,4]输出:false示例3:输入:root=[]......
  • #yyds干货盘点# LeetCode程序员面试金典:分数到小数
    1.简述:给定两个整数,分别表示分数的分子 numerator和分母denominator,以字符串形式返回小数。如果小数部分为循环小数,则将循环的部分括在括号内。如果存在多个答案,只需返回任意一个。对于所有给定的输入,保证答案字符串的长度小于104。 示例1:输入:numerator=1,denominat......
  • LeetCode 103. 二叉树的锯齿形层次遍历
    classSolution{public:vector<vector<int>>res;voidbfs(TreeNode*root){queue<TreeNode*>q;q.push(root);intcnt=0;while(!q.empty()){vector<int>level;......
  • LeetCode 周赛 346(2023/05/21)仅 68 人 AK 的最短路问题
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]提问。LeetCode单周赛第345场·体验一题多解的算法之美单周赛345概览T1.删除子串后的字符串最小长度(Easy)标签:栈T2.字典序最小回文串(Medium)标签:贪心、双指针T3.求一个整数的惩罚数(Medium)标签......
  • leetcode724
    使用数学方法:假设左边的所有数加起来的和是sum,total为数组所有元素加起来的和,当i满足中心下标的条件时,即:sum=total-sum-nums[i];2*sum+nums[i]=total;当中心下标是首位时,即左边sum为0;当中心下标是尾位时,右边total-sum-nums[i]为0;for(inti=0;i<n;++i){if(2*sum+nums[i]==......
  • 图解LeetCode——19. 删除链表的倒数第 N 个结点
    一、题目给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。二、示例2.1>示例1:【输入】head=[1,2,3,4,5],n=2【输出】[1,2,3,5]2.2>示例2:【输入】head=[1],n=1【输出】[]2.3>示例3:【输入】head=[1,2],n=1【输出】[1]提示:链......
  • #yyds干货盘点# LeetCode程序员面试金典:有序链表转换二叉搜索树
    题目:给定一个单链表的头节点 head ,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过1。 示例1:输入:head=[-10,-3,0,5,9]输出:[0,-3,9,-10,null,5]解释:一个可能的答案是[0,-3,9,-1......
  • #yyds干货盘点# LeetCode程序员面试金典:比较版本号
    1.简述:给你两个版本号version1和version2,请你比较它们。版本号由一个或多个修订号组成,各修订号由一个'.'连接。每个修订号由多位数字组成,可能包含前导零。每个版本号至少包含一个字符。修订号从左到右编号,下标从0开始,最左边的修订号下标为0,下一个修订号下标为1,以此......
  • LeetCode 746.使用最小花费爬楼梯
    1.题目:给你一个整数数组cost,其中cost[i]是从楼梯第i个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为0或下标为1的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。示例1:输入:cost=[10,15,20]输出:15解释:你......