当前位置: 首页 > news >正文

代码随想录算法训练Day57|LeetCode200-岛屿数量、LeetCode695-岛屿的最大面积

岛屿数量

题目描述

力扣200-岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 2:

输入:grid = [["1","1","0","0","0"],["1","1","0","0","0"],["0","0","1","0","0"],["0","0","0","1","1"]
]
输出:3

图一

本题思路,是用遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都标记上。在遇到标记过的陆地节点和海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。

那么如果把节点陆地所能遍历到的陆地都标记上呢,就可以使用 DFS,BFS或者并查集。

广度优先搜索 BFS

不少同学用广搜做这道题目的时候,超时了。 这里有一个广搜中很重要的细节:

根本原因是==只要 加入队列就代表 走过,就需要标记,而不是从队列拿出来的时候再去标记走过==。

很多同学可能感觉这有区别吗?

如果从队列拿出节点,再去标记这个节点走过,就会发生下图所示的结果,会导致很多节点重复加入队列。

图二

 `visited[x][y] = true;` 放在的地方,着去取决于我们对 代码中队列的定义,队列中的节点就表示已经走过的节点。 **所以只要加入队列,立即标记该节点走过**

本题完整广搜代码:

class Solution {private static final int[][] dir = { { 0, 1 }, { 1, 0 }, { -1, 0 }, { 0, -1 } }; // 四个方向private void bfs(char[][] grid, boolean[][] visited, int x, int y) {//用于将当前陆地相连的陆地都进行标记Queue<int[]> queue = new LinkedList<>();queue.add(new int[] { x, y });visited[x][y] = true; // 只要加入队列,立刻标记while (!queue.isEmpty()) {int[] cur = queue.poll();int curx = cur[0];// 取出当前节点(curx,cury)int cury = cur[1];// 遍历四个方向,如果相邻节点(nextx,nexty)在网格内切未被访问过,并且其是陆地(1),则将其加入到队列,并将其标记为已访问for (int[] d : dir) {int nextx = curx + d[0];int nexty = cury + d[1];if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length)continue; // 越界了,直接跳过if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') {queue.add(new int[] { nextx, nexty });visited[nextx][nexty] = true; // 只要加入队列立刻标记}}} // 循环直到队列为空,即所有与起始点连通的陆地都被标记为已访问}public int numIslands(char[][] grid) {int n = grid.length;int m = grid[0].length;boolean[][] visited = new boolean[n][m];// 二维布尔数组visited,用于标记网格中每个位置是否已被访问过int result = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (!visited[i][j] && grid[i][j] == '1') {// 当前位置 未访问过的且是陆地,岛屿数量+1result++; // 遇到没访问过的陆地,+1bfs(grid, visited, i, j); // 将与其链接的陆地都标记上 true}}}return result;}
}

深度优先搜索 DFS—模板

//DFS
class Solution {private int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 四个方向private void dfs(char[][] grid, boolean[][] visited, int x, int y) {for (int[] d : dir) {int nextx = x + d[0];int nexty = y + d[1];if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) continue;  // 越界了,直接跳过if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') { // 没有访问过的同时是陆地的visited[nextx][nexty] = true; dfs(grid, visited, nextx, nexty);} }}public int numIslands(char[][] grid) {int n = grid.length;int m = grid[0].length;boolean[][] visited = new boolean[n][m];int result = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (!visited[i][j] && grid[i][j] == '1') { visited[i][j] = true;result++; // 遇到没访问过的陆地,+1dfs(grid, visited, i, j); // 将与其链接的陆地都标记上 true}}}return result;}
}

下面的代码使用的是深度优先搜索 DFS 的做法。为了统计岛屿数量同时不重复记录,每当我们搜索到一个岛后,就将这个岛 “淹没” —— 将这个岛所占的地方从 “1” 改为 “0”,这样就不用担心后续会重复记录这个岛屿了。而 DFS 的过程就体现在 “淹没” 这一步中。详见代码:

public int numIslands(char[][] grid) {int res = 0; //记录找到的岛屿数量for(int i = 0;i < grid.length;i++){for(int j = 0;j < grid[0].length;j++){//找到“1”,res加一,同时淹没这个岛if(grid[i][j] == '1'){res++;dfs(grid,i,j);}}}return res;
}
//使用DFS“淹没”岛屿
public void dfs(char[][] grid, int i, int j){//搜索边界:索引越界或遍历到了"0"if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0') return;//将这块土地标记为"0"grid[i][j] = '0';//根据"每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成",对上下左右的相邻顶点进行dfsdfs(grid,i - 1,j);dfs(grid,i + 1,j);dfs(grid,i,j + 1);dfs(grid,i,j - 1);
}

岛屿的最大面积

题目描述

力扣695-岛屿的最大面积

给你一个大小为 m x n 的二进制矩阵 grid

岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻(斜角度的不算)。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

岛屿的面积是岛上值为 1 的单元格的数目。

计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0

示例 1:

img

输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。

示例 2:

输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0

解题思路

这道题目也是 dfs bfs基础类题目,就是搜索每个岛屿上“1”的数量,然后取一个最大的。

本题思路上比较简单,难点其实都是 dfs 和 bfs的理论基础,关于理论基础我在这里都有详细讲解 :

DFS理论基础(opens new window)

BFS理论基础

根据BFS模板

//BFS
class Solution {private int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 表示四个方向void bfs(char[][] grid, boolean[][] visited, int x, int y) {Queue<int[]> queue = new LinkedList<>(); // 定义队列queue.offer(new int[]{x, y}); // 起始节点加入队列visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点while (!queue.isEmpty()) { // 开始遍历队列里的元素int[] cur = queue.poll(); // 从队列取元素int curx = cur[0];int cury = cur[1]; // 当前节点坐标for (int i = 0; i < 4; i++) { // 开始向当前节点的四个方向左右上下去遍历int nextx = curx + dir[i][0];int nexty = cury + dir[i][1]; // 获取周围四个方向的坐标if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) continue;  // 坐标越界了,直接跳过if (!visited[nextx][nexty]) { // 如果节点没被访问过queue.offer(new int[]{nextx, nexty}); // 队列添加该节点为下一轮要遍历的节点visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问}}}}
}

BFS

//BFS
class Solution {int[][] dir = {{ 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 }};int count;boolean visited[][];public int maxAreaOfIsland(int[][] grid) {int res = 0;visited = new boolean[grid.length][grid[0].length];for (int i = 0; i < grid.length; i++) {for (int j = 0; j < grid[0].length; j++) {if (visited[i][j] == false && grid[i][j] == 1) {count = 0;bfs(grid, i, j);res = Math.max(res, count);}}}return res;}private void bfs(int[][] grid, int x, int y) {Queue<int[]> queue = new LinkedList<>(); // 定义队列queue.offer(new int[] { x, y }); // 起始节点加入队列visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点count++; // 将起始节点也算入岛屿面积中while (!queue.isEmpty()) { // 开始遍历队列里的元素int[] cur = queue.poll(); // 从队列取元素int curx = cur[0];int cury = cur[1]; // 当前节点坐标for (int i = 0; i < 4; i++) { // 开始向当前节点的四个方向左右上下去遍历int nextx = curx + dir[i][0];int nexty = cury + dir[i][1]; // 获取周围四个方向的坐标if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length)continue;if (visited[nextx][nexty] == false && grid[nextx][nexty] == 1) {queue.offer(new int[] { nextx, nexty }); // 队列添加该节点为下一轮要遍历的节点visited[nextx][nexty] = true;count++;}}}}}

根据DFS模板

//DFS
class Solution {private int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 四个方向private void dfs(char[][] grid, boolean[][] visited, int x, int y) {for (int[] d : dir) {int nextx = x + d[0];int nexty = y + d[1];if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) continue;  // 越界了,直接跳过if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') { // 没有访问过的同时是陆地的visited[nextx][nexty] = true; dfs(grid, visited, nextx, nexty);} }}public int numIslands(char[][] grid) {int n = grid.length;int m = grid[0].length;boolean[][] visited = new boolean[n][m];int result = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (!visited[i][j] && grid[i][j] == '1') { visited[i][j] = true;result++; // 遇到没访问过的陆地,+1dfs(grid, visited, i, j); // 将与其链接的陆地都标记上 true}}}return result;}
}

DFS

//DFS
class Solution {private int count;private int[][] dir = { { 0, 1 }, { 1, 0 }, { -1, 0 }, { 0, -1 } }; // 四个方向private void dfs(int[][] grid, boolean[][] visited, int x, int y) {for (int[] d : dir) {int nextx = x + d[0];int nexty = y + d[1];if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length)continue; // 越界了,直接跳过if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) { // 没有访问过的 同时 是陆地的visited[nextx][nexty] = true;count++;dfs(grid, visited, nextx, nexty);}}}public int maxAreaOfIsland(int[][] grid) {int n = grid.length;int m = grid[0].length;boolean[][] visited = new boolean[n][m];int result = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (!visited[i][j] && grid[i][j] == 1) {count = 1; // 因为dfs处理下一个节点,所以这里遇到陆地了就先计数,dfs处理接下来的相邻陆地visited[i][j] = true;dfs(grid, visited, i, j); // 将与其链接的陆地都标记上 trueresult = Math.max(result, count);}}}return result;}
}

ps:部分图片和代码来自代码随想录和Leetcode官网

相关文章:

代码随想录算法训练Day57|LeetCode200-岛屿数量、LeetCode695-岛屿的最大面积

岛屿数量 题目描述 力扣200-岛屿数量 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此…...

StopWatch的使用

org.springframework.util.StopWatch 是 Spring 框架提供的一个轻量级的计时工具&#xff0c;用于测量代码执行时间。它比 Apache Commons Lang 的 StopWatch 提供了更多的功能&#xff0c;例如累计多个时间段、打印详细报告等。 以下是如何使用 Spring 的 StopWatch&#xff…...

MySQL基础篇(三)数据库的修改 删除 备份恢复 查看连接情况

对数据库的修改主要指的是修改数据库的字符集&#xff0c;校验规则。 将test1数据库字符集改为gbk。 数据库的删除&#xff1a; 执行完该数据库就不存在了&#xff0c;对应数据库文件夹被删除&#xff0c;级联删除&#xff0c;里面的数据表全部被删除。 注意&#xff1a;不要随…...

android手机电视相框项目-学员做出个bug版本邀请大家review提意见

背景 前几天给我的vip学员布置了一个android手机/电视相框的项目&#xff0c;具体详情看如下链接&#xff1a; https://mp.weixin.qq.com/s/l2roDoco-o59SLlORENZlA 这个项目我说过不给提供答案哈&#xff0c;让各位学员朋友自己独立思考完成哈&#xff0c;因为尽量想让大家慢…...

web零碎知识2

不知道我的这个axios的包导进去没。 找一下关键词&#xff1a; http请求协议&#xff1a;就是进行交互式的格式 需要定义好 这个式一发一收短连接 而且没有记忆 这个分为三个部分 第一个式请求行&#xff0c;第二个就是请求头 第三个就是请求体 以get方式进行请求的失手请求…...

Android项目框架

Android项目基于Android Studio开发&#xff0c;Android Studio使用Gradle作为项目构建工具。新建工程后可以看到如图所示目录结构&#xff0c;将Android切成Project可以看到完整的Android工程目录结构&#xff0c;如图所示。 图1-2 Android项目目录结构 app目录是一个典型的…...

vue 模糊查询加个禁止属性

vue 模糊查询加个禁止属性 父组件通过属性传&#xff0c;是否禁止输入-------默认可以输入...

MySQL 主从复制中 MHA 工具的研究与实践

MySQL 主从复制中 MHA 工具的研究与实践 一、MHA 工具简介二、MHA 的工作原理三、MHA 配置步骤环境准备1. 在主服务器上配置主从复制2. 在从服务器上配置复制 安装 MHA 工具1. 安装必要的依赖包2. 下载并安装 MHA 配置 MHA1. 创建 MHA 配置文件2. 配置 SSH 免密登录 测试 MHA1.…...

Hi3861 OpenHarmony嵌入式应用入门--TCP Server

本篇使用的是lwip编写tcp服务端。需要提前准备好一个PARAM_HOTSPOT_SSID宏定义的热点&#xff0c;并且密码为PARAM_HOTSPOT_PSK LwIP简介 LwIP是什么&#xff1f; A Lightweight TCP/IP stack 一个轻量级的TCP/IP协议栈 详细介绍请参考LwIP项目官网&#xff1a;lwIP - A Li…...

Poker Game, Run Fast

Poker Game, Run Fast 扑克&#xff1a;跑得快 分门别类&#xff1a; 单张从小到大默认 A < 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K 跑得快&#xff1a;单张从小到大 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 &…...

订单折扣金额分摊算法|代金券分摊|收银系统|积分分摊|分摊|精度问题|按比例分配|钱分摊|钱分配

一个金额分摊的算法&#xff0c;将折扣分摊按比例&#xff08;细单实收在总体的占比&#xff09;到各个细单中。 此算法需要达到以下要求&#xff1a; 折扣金额接近细单总额&#xff0c;甚至折扣金额等于细单金额&#xff0c;某些时候甚至超过细单总额&#xff0c;要保证实收不…...

Matlab中collectPlaneWave函数的应用

查看文档如下&#xff1a; 可以看出最多5个参数&#xff0c;分别是阵列对象&#xff0c;信号幅度&#xff0c;入射角度&#xff0c;信号频率&#xff0c;光速。 在下面的代码中&#xff0c;我们先创建一个3阵元的阵列&#xff0c;位置为&#xff1a;&#xff08;-1,0,0&#x…...

Linux系统的基础知识和常用命令

1、什么是Linux&#xff1f; 是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹于1991年10月5日首次发布&#xff0c;它主要受到Minix和Unix思想的启发&#xff0c;是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行…...

三相异步电动机的起动方法

1. 引言 2. 三相笼型异步电动机德起动方法 3. 三相绕线型异步电动机的起动方法 4. 软起动器起动 5. 参考文献 1 引言 三相异步电动机结构简单﹑价格低廉﹑运行可靠﹑维护方便&#xff0c;在工农业生产中得到了广泛应用。为使电动机能够转动起来&#xff0c;并很快达到工作转…...

【LinuxC语言】手撕Http协议之accept_request函数实现(一)

文章目录 前言accept_request函数作用accept_request实现解析方法根据不同方法进行不同操作http服务器响应格式unimplemented函数实现总结前言 在计算机网络中,HTTP协议是一种常见的应用层协议,它定义了客户端和服务器之间如何进行数据交换。在这篇文章中,我们将深入探讨Li…...

Redis Cluster 模式 的具体实施细节是什么样的?

概述 参考&#xff1a;What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium Redis Cluster 的工作原理是将数据分布在多个节点上&#xff0c;同时确保高可用性和容错能力。以下是 Redis Cluster 运行方式的简要概述&#xff1a; …...

基于大模型的机器人控制

基于大模型的机器人控制是指利用深度学习中的大型神经网络模型来实现对机器人的精确控制。这种方法结合了深度学习的强大表征学习能力和机器人控制的实际需求&#xff0c;旨在提高机器人的自主性、灵活性和智能性。 基本原理 数据收集&#xff1a;首先&#xff0c;需要收集大量…...

在 PostgreSQL 中,如何处理数据的版本控制?

文章目录 一、使用时间戳字段进行版本控制二、使用版本号字段进行版本控制三、使用历史表进行版本控制四、使用 RETURNING 子句获取更新前后的版本五、使用数据库触发器进行版本控制 在 PostgreSQL 中&#xff0c;处理数据的版本控制可以通过多种方式实现&#xff0c;每种方式都…...

Rust 组织管理

Rust 组织管理 Rust 是一种系统编程语言&#xff0c;以其内存安全性、速度和并发性而闻名。它由 Mozilla 开发&#xff0c;并得到了一个庞大而活跃的社区的支持。Rust 的组织管理涉及多个方面&#xff0c;包括项目管理、社区参与、工具和库的维护&#xff0c;以及生态系统的整…...

vb.netcad二开自学笔记1:万里长征第一步Hello CAD!

已入门的朋友请绕行&#xff01; 今天开启自学vb.net 开发autocad&#xff0c;网上相关资料太少了、太老了。花钱买课吧&#xff0c;穷&#xff01;又舍不得&#xff0c;咬牙从小白开始摸索自学吧&#xff0c;虽然注定是踏上了一条艰苦之路&#xff0c;顺便作个自学笔记备忘!积…...

Vue的学习之数据与方法

前段期间&#xff0c;由于入职原因没有学习&#xff0c;现在已经正式入职啦&#xff0c;接下来继续加油学习。 一、数据与方法 文字备注已经在代码中&#xff0c;方便自己学习和理解 <!DOCTYPE html> <html><head><meta charset"utf-8">&l…...

刷题——在二叉树中找到最近公共祖先

在二叉树中找到两个节点的最近公共祖先_牛客题霸_牛客网 int lowestCommonAncestor(TreeNode* root, int o1, int o2) {if(root NULL) return -1;if((root->val o1) || (root->val o2)) return root->val;int left lowestCommonAncestor(root->left, o1, o2);i…...

nginx(三)—从Nginx配置熟悉Nginx功能

一、 Nginx配置文件结构 ... #全局块events { #events块... }http #http块 {... #http全局块server #server块{ ... #server全局块location [PATTERN] #location块{...}location [PATTERN] {...}}server{...}... #http全局块 …...

Python轮子:文件比较器——filecmp

原文链接&#xff1a;http://www.juzicode.com/python-module-filecmp filecmp模块可以用来比较文件或者目录。 安装和导入 filecmp是Python自带的模块&#xff0c;不需要额外安装&#xff0c;直接导入即可&#xff1a; import filecmp as fc #或者 import filecmp cmp()比较…...

uni-app组件 子组件onLoad、onReady事件无效

文章目录 导文解决方法 导文 突然发现在项目中&#xff0c;组件 子组件的onLoad、onReady事件无效 打印也出不来值 怎么处理呢&#xff1f; 解决方法 mounted() {console.log(onLoad, this.dateList);//有效// this.checkinDetails()},onReady() {console.log(onReady, this.da…...

leetcode力扣_排序问题

215.数组中的第K个最大元素 鉴于已经将之前学的排序算法忘得差不多了&#xff0c;只会一个冒泡排序法了&#xff0c;就写了一个冒牌排序法&#xff0c;将给的数组按照降序排列&#xff0c;然后取nums[k-1]就是题目要求的&#xff0c;但是提交之后对于有的示例显示”超出时间限制…...

在 .NET 8 Web API 中实现弹性

在现代 Web 开发中&#xff0c;构建弹性 API 对于确保可靠性和性能至关重要。本文将指导您使用 Microsoft.Extensions.Http.Resilience 库在 .NET 8 Web API 中实现弹性。我们将介绍如何设置重试策略和超时&#xff0c;以使您的 API 更能抵御瞬时故障。 步骤 1.创建一个新的 .…...

linux下高级IO模型

高级IO 1.高级IO模型基本概念1.1 阻塞IO1.2 非阻塞IO1.3 信号驱动IO1.4 IO多路转接1.5 异步IO 2. 模型代码实现2.1 非阻塞IO2.2 多路转接-selectselect函数介绍什么才叫就绪呢&#xff1f;demoselect特点 2.3 多路转接-pollpoll函数介绍poll优缺点demo 2.4 多路转接-epoll&…...

掌握Mojolicious会话管理:构建安全、持久的Web应用

掌握Mojolicious会话管理&#xff1a;构建安全、持久的Web应用 Mojolicious是一个基于Perl的高性能、异步Web开发框架&#xff0c;它提供了一套完整的工具来构建现代Web应用。会话管理是Web开发中的一个关键组成部分&#xff0c;它允许应用识别和保持用户的登录状态。本文将深…...

24西安电子科技大学马克思主义学院—考研录取情况

01、马克思主义学院各个方向 02、24马克思主义学院近三年复试分数线对比 PS&#xff1a;马院24年院线相对于23年院线增加15分&#xff0c;反映了大家对于马克思主义理论学习与研究的热情高涨&#xff0c;也彰显了学院在人才培养、学科建设及学术研究等方面的不断进步与成就。 6…...