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

news2024/11/24 20:38:16

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

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

🚀 运行结果:

在这里插入图片描述

🕔 复杂度分析:

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

题目来源:力扣。

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

注: 如有不足,欢迎指正!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1021695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redisplusplus笔记

redis与连接 Redis处理命令 connection主要方法及与reply关系 connection只支持移动语义&#xff0c;不支持拷贝和赋值 recv使用ReplyUPtr&#xff0c;即unique_ptr<redisReply, ReplyDeleter>,其中ReplyDeleter定义如下 struct ReplyDeleter {void operator()(redis…

从0搭建夜莺v6基础监控告警系统(二):采集数据、打通夜莺显示

文章目录 1. 写在前面1.1. categraf 采集数据1.2. 官方文档传送门 2. 配置过程2.1. 打通夜莺和 VictoriaMetrics2.2. 配置 Categraf2.3. 验证结果2.4. 配置仪表盘 3. 部署总结3.1. 操作总结3.2. 仪表盘展示 上一操作我们已经安装好了所需的基础服务&#xff0c;接下来需要打通各…

AI项目八:yolo5+Deepsort实现目标检测与跟踪(CPU版)

若该文为原创文章&#xff0c;转载请注明原文出处。 一、DeepSORT简介 DeepSORT 是一种计算机视觉跟踪算法&#xff0c;用于在为每个对象分配 ID 的同时跟踪对象。DeepSORT 是 SORT&#xff08;简单在线实时跟踪&#xff09;算法的扩展。DeepSORT 将深度学习引入到 SORT 算法中…

Android.bp常用语法和预定义属性

介绍 Android.bp是Android构建系统中用于定义模块和构建规则的配置文件&#xff0c;它使用一种简单的声明式语法。以下是Android.bp的一些常见语法规则和约定&#xff1a; 注释&#xff1a; 单行注释使用//符号。 多行注释使用/和/包围。 和go语言相同 // 这是单行注释 /* 这是…

爆破shadow文件密码脚本(完成版)

在之前的博客Python爆破shadow文件密码脚本&#xff08;简化版&#xff09;中我们做了简化版的爆破shadow文件密码的python脚本&#xff0c;接下来在之前代码的基础上改进&#xff1a; import crypt shadow_line"root:$y$j9T$uEgezfJhn7Ov5naU8bzZt.$9qIqkWYObaXajS5iLDA…

charles报错Not allowed GET http://xx.xx.com/xx - connection dropped

现象&#xff1a;手机抓包时&#xff0c;charles提示Not allowed GET http://xx.xx.com/xx - connection&#xff0c;请求status显示block 排查原因&#xff1a; 1、换手机连接抓包工具&#xff0c;现象也是同上&#xff0c;可以排除手机的原因 2、检索网络上关于报错的解决方…

【HCIE】08.MPLS VPN跨域AB

MPLS VPN跨域A ASBR之间交换IPV4路由&#xff0c;采用IPVR数据包转发数据。该方式易于理解 跨域的要求 两个ASBR之间不能开启LDP&#xff0c;可以开启MPLS 因为两个路由器处于不同的AS之间&#xff0c;之间的IGP是不能互通的&#xff0c;之前是没有路由的 之所以中间不能开…

Java | 网络编程

不爱生姜不吃醋⭐️ 如果本文有什么错误的话欢迎在评论区中指正 与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 &#x1f334;前言&#x1f334;一、网络编程1.概念2.常见软件架构 &#x1f334;二、网络编程三要素1. IP2. 端口号3.协议 &#x1f334;总结 &…

Mybatis学习笔记7 参数处理专题

Mybatis学习笔记6 使用时的一些小技巧_biubiubiu0706的博客-CSDN博客 1.单个简单类型参数 2.Map参数 3.实体类参数 4.多参数 5.Param注解(命名参数) 6.Param源码分析 建表 插入点数据 新建模块 pom.xml <?xml version"1.0" encoding"UTF-8"?&…

STM32 USB CDC 虚拟串口

// 用虚拟串口(USB CDC VCP)感觉有些不稳定&#xff0c;尤其是下位机掉电后再上电&#xff0c;上位机虚拟的那个串口根本不能用&#xff0c;还有就是 // 必须等虚拟串口出来后且知道串口号上位机才可以执行打开操作// 上面是实际情况&#xff0c;但并不是STM32的USB不行&#x…

JUnit5单元测试提示“Not tests were found”错误

JUnit5单元测试提示“Not tests were found”错误&#xff0c;如下图所示&#xff1a; 或者 问题解析&#xff1a; 1&#xff09;使用Test注解时&#xff0c;不能有返回值&#xff1b; 2&#xff09;使用Test注解时&#xff0c;不能使用private关键字&#xff1b; 存在以上情…

C语言——贪吃蛇小游戏

目录 一、ncurse 1.1 为什么需要用ncurse&#xff1a; 1.2 ncurse的输入输出&#xff1a; 1.2.1 如何使用ncurse&#xff1a; 1.2.2 编译ncurse的程序&#xff1a; 1.2.3 测试输入一个按键ncurse的响应速度&#xff1a; 1.3 ncurse上下左右键获取&#xff1a; 1.3.1 如…

移动 Web 第一天

目标&#xff1a;使用位移、缩放、旋转、渐变效果丰富网页元素的呈现方式。 文章目录 01-平面转换简介平移定位居中案例-双开门旋转转换原点案例-时钟多重转换缩放案例-播放特效倾斜 02-渐变线性渐变案例-产品展示径向渐变 03-综合案例导航-频道箭头旋转频道列表 渐变按钮搜索…

什么是AJAX?如何使用原生JavaScript进行AJAX请求?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是AJAX&#xff1f;⭐如何使用原生JavaScript进行AJAX请求&#xff1f;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为…

【ONE·Linux || 进程间通信(一)】

总言 进程间通信&#xff1a;简述进程间通信&#xff0c;介绍通信方式之一&#xff0c;管道通信&#xff08;匿名、名命&#xff09;。 文章目录 总言1、进程间通信简述2、管道2.1、简介2.2、匿名管道2.2.1、匿名管道的原理2.2.2、编码理解&#xff1a;用fork来共享管道2.2.2.…

Rocketmq--消息发送和接收演示

使用Java代码来演示消息的发送和接收 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.0.2</version> </dependency> 1 发送消息 消息发送步骤: 创建…

三维模型3DTile格式轻量化压缩必要性分析

三维模型3DTile格式轻量化压缩必要性分析 理解3DTile格式轻量化压缩的必要性&#xff0c;首先需要理解三维模型的复杂性和数据量。三维模型通常包含大量的顶点、面片和纹理信息&#xff0c;这使得其数据量非常大&#xff0c;尤其对于大规模的三维地理空间数据&#xff0c;例如城…

Python:为何成为当下最热门的编程语言?

文章目录 &#x1f34b;引言&#x1f34b;1. 简单易学&#x1f34b;2. 多领域应用&#x1f34b;3. 强大的社区支持&#x1f34b;4. 丰富的库和框架&#x1f34b;5. 跨平台兼容&#x1f34b;6. 开源和免费&#x1f34b;7. 数据科学和人工智能的崛起&#x1f34b;8. 自动化和脚本…

YOLOv3深度解析【未完待续】

概况 &#xff08;1&#xff09;YOLOv3是YOLO系列第一次引入残差连接来解决深度网络中的梯度消失问题&#xff08;是不是第一次&#xff0c;有待你后面考证&#xff09;&#xff0c;实际用的backbone是DarkNet53 &#xff08;2&#xff09;最显著的改进&#xff0c;也是对你涨…

【SpringMVC】基于 Spring 的 Web 层MVC 框架

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理SpringMVC : 基于 Spring 的 Web 层MVC 框架 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一下…