news 2026/9/3 1:24:30

代码随想录算法训练营第四十四天:孤岛计数(广搜版),孤岛计数(深搜版),最大岛屿的面积

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代码随想录算法训练营第四十四天:孤岛计数(广搜版),孤岛计数(深搜版),最大岛屿的面积

孤岛计数

深搜版文章讲解/视频讲解

广搜版文章讲解/视频讲解

题目描述:

给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。

输入描述:

第一行包含两个整数 N, M,表示矩阵的行数和列数。

后续 N 行,每行包含 M 个数字,数字为 1 或者 0。

输出描述:

输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。

输入示例:

4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1

输出示例:

3

提示信息

根据测试案例中所展示,岛屿数量共有 3 个,所以输出 3。

数据范围:

  • 1 <= N, M <= 50

思路:

本题中的每座岛屿都只能由水平方向和/或竖直方向上相邻的陆地连接形成,也就是说斜角度的连接是不算数的,如图,这是三个岛屿:

那么思路就是遇到一个没有遍历过的节点陆地,就让计数器加一,然后把节点陆地所能遍历到的陆地全部标记上。如果遇到了标记过的陆地节点和海洋节点就直接跳过,这样计数器就是最终岛屿的数量,所以我们本题标记所有陆地节点能遍历到的陆地的方式就可以选择dfs和bfs了。

dfs代码示例:

const r1 = require('readline').createInterface({ input: process.stdin }); // 创建readline接口 let iter = r1[Symbol.asyncIterator](); // 创建异步迭代器 const readline = async () => (await iter.next()).value; let graph let N, M let visited let result = 0 const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] // 读取输入,初始化地图 const initGraph = async () => { let line = await readline(); [N, M] = line.split(' ').map(Number); graph = new Array(N).fill(0).map(() => new Array(M).fill(0)) visited = new Array(N).fill(false).map(() => new Array(M).fill(false)) for (let i = 0; i < N; i++) { line = await readline() line = line.split(' ').map(Number) for (let j = 0; j < M; j++) { graph[i][j] = line[j] } } } /** * @description: 从节点x,y开始深度优先遍历 * @param {*} graph 是地图,也就是一个二维数组 * @param {*} visited 标记访问过的节点,不要重复访问 * @param {*} x 表示开始搜索节点的下标 * @param {*} y 表示开始搜索节点的下标 * @return {*} */ const dfs = (graph, visited, x, y) => { for (let i = 0; i < 4; i++) { const nextx = x + dir[i][0] const nexty = y + dir[i][1] if (nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue if (!visited[nextx][nexty] && graph[nextx][nexty] === 1) { visited[nextx][nexty] = true dfs(graph, visited, nextx, nexty) } } } (async function () { // 读取输入,初始化地图 await initGraph() // 统计岛屿数 for (let i = 0; i < N; i++) { for (let j = 0; j < M; j++) { if (!visited[i][j] && graph[i][j] === 1) { // 标记已访问 visited[i][j] = true // 遇到没访问过的陆地,+1 result++ // 深度优先遍历,将相邻陆地标记为已访问 dfs(graph, visited, i, j) } } } console.log(result); })()

bfs有一个值得注意的点,只要是加入队列就代表走过了,就需要标记,而不是从队列拿出来的时候再去标记走过,如果从队列拿出结点再标记,就会出现以下情况,导致节点重复加入队列:

bfs代码示例:

const r1 = require('readline').createInterface({ input: process.stdin }); // 创建readline接口 let iter = r1[Symbol.asyncIterator](); // 创建异步迭代器 const readline = async () => (await iter.next()).value; let graph let N, M let visited let result = 0 const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] // 读取输入,初始化地图 const initGraph = async () => { let line = await readline(); [N, M] = line.split(' ').map(Number); graph = new Array(N).fill(0).map(() => new Array(M).fill(0)) visited = new Array(N).fill(false).map(() => new Array(M).fill(false)) for (let i = 0; i < N; i++) { line = await readline() line = line.split(' ').map(Number) for (let j = 0; j < M; j++) { graph[i][j] = line[j] } } } /** * @description: 从(x, y)开始广度优先遍历 * @param {*} graph 地图 * @param {*} visited 访问过的节点 * @param {*} x 开始搜索节点的下标 * @param {*} y 开始搜索节点的下标 * @return {*} */ const bfs = (graph, visited, x, y) => { let queue = [] queue.push([x, y]) visited[x][y] = true //只要加入队列就立刻标记为访问过 while (queue.length) { let [x, y] = queue.shift() for (let i = 0; i < 4; i++) { let nextx = x + dir[i][0] let nexty = y + dir[i][1] if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){ queue.push([nextx, nexty]) visited[nextx][nexty] = true } } } } (async function () { // 读取输入,初始化地图 await initGraph() // 统计岛屿数 for (let i = 0; i < N; i++) { for (let j = 0; j < M; j++) { if (!visited[i][j] && graph[i][j] === 1) { // 遇到没访问过的陆地,+1 result++ // 广度优先遍历,将相邻陆地标记为已访问 bfs(graph, visited, i, j) } } } console.log(result); })()

最大岛屿的面积

文章讲解/视频讲解

题目描述

给定一个由 1(陆地)和 0(水)组成的矩阵,计算岛屿的最大面积。岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。

输入描述

第一行包含两个整数 N, M,表示矩阵的行数和列数。后续 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。

输出描述

输出一个整数,表示岛屿的最大面积。如果不存在岛屿,则输出 0。

输入示例

4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1

输出示例

4

提示信息

样例输入中,岛屿的最大面积为 4。

数据范围:

  • 1 <= M, N <= 50。

思路:

本题还是dfs与bfs的基础类题目,就是去搜索每个岛屿上‘1’的数量,然后取一个最大的

dfs:两种写法,要么dfs处理当前节点的相邻节点,即主函数遇到岛屿就计数为1,由dfs来处理接下来的相邻陆地。还有一种写法是dfs处理当前节点,即主函数遇到岛屿计数为0,dfs处理的是接下来全部的陆地

这里我是用解法一:

const r1 = require('readline').createInterface({ input: process.stdin }); // 创建readline接口 let iter = r1[Symbol.asyncIterator](); // 创建异步迭代器 const readline = async () => (await iter.next()).value; let graph // 地图 let N, M // 地图大小 let visited // 访问过的节点 let result = 0 // 最大岛屿面积 let count = 0 // 岛屿内节点数 const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向 // 读取输入,初始化地图 const initGraph = async () => { let line = await readline(); [N, M] = line.split(' ').map(Number); graph = new Array(N).fill(0).map(() => new Array(M).fill(0)) visited = new Array(N).fill(false).map(() => new Array(M).fill(false)) for (let i = 0; i < N; i++) { line = await readline() line = line.split(' ').map(Number) for (let j = 0; j < M; j++) { graph[i][j] = line[j] } } } /** * @description: 从(x, y)开始深度优先遍历 * @param {*} graph 地图 * @param {*} visited 访问过的节点 * @param {*} x 开始搜索节点的下标 * @param {*} y 开始搜索节点的下标 * @return {*} */ const dfs = (graph, visited, x, y) => { for (let i = 0; i < 4; i++) { let nextx = x + dir[i][0] let nexty = y + dir[i][1] if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){ count++ visited[nextx][nexty] = true dfs(graph, visited, nextx, nexty) } } } (async function () { // 读取输入,初始化地图 await initGraph() // 统计最大岛屿面积 for (let i = 0; i < N; i++) { for (let j = 0; j < M; j++) { if (!visited[i][j] && graph[i][j] === 1) { //遇到没有访问过的陆地 // 重新计算面积 count = 1 visited[i][j] = true // 深度优先遍历,统计岛屿内节点数,并将岛屿标记为已访问 dfs(graph, visited, i, j) // 更新最大岛屿面积 result = Math.max(result, count) } } } console.log(result); })()

bfs就直接一种写法:

const r1 = require('readline').createInterface({ input: process.stdin }); // 创建readline接口 let iter = r1[Symbol.asyncIterator](); // 创建异步迭代器 const readline = async () => (await iter.next()).value; let graph // 地图 let N, M // 地图大小 let visited // 访问过的节点 let result = 0 // 最大岛屿面积 let count = 0 // 岛屿内节点数 const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向 // 读取输入,初始化地图 const initGraph = async () => { let line = await readline(); [N, M] = line.split(' ').map(Number); graph = new Array(N).fill(0).map(() => new Array(M).fill(0)) visited = new Array(N).fill(false).map(() => new Array(M).fill(false)) for (let i = 0; i < N; i++) { line = await readline() line = line.split(' ').map(Number) for (let j = 0; j < M; j++) { graph[i][j] = line[j] } } } /** * @description: 从(x, y)开始广度优先遍历 * @param {*} graph 地图 * @param {*} visited 访问过的节点 * @param {*} x 开始搜索节点的下标 * @param {*} y 开始搜索节点的下标 * @return {*} */ const bfs = (graph, visited, x, y) => { let queue = [] queue.push([x, y]) count++ visited[x][y] = true //只要加入队列就立刻标记为访问过 while (queue.length) { let [xx, yy] = queue.shift() for (let i = 0; i < 4; i++) { let nextx = xx + dir[i][0] let nexty = yy + dir[i][1] if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){ queue.push([nextx, nexty]) count++ visited[nextx][nexty] = true } } } } (async function () { // 读取输入,初始化地图 await initGraph() // 统计最大岛屿面积 for (let i = 0; i < N; i++) { for (let j = 0; j < M; j++) { if (!visited[i][j] && graph[i][j] === 1) { //遇到没有访问过的陆地 // 重新计算面积 count = 0 // 广度优先遍历,统计岛屿内节点数,并将岛屿标记为已访问 bfs(graph, visited, i, j) // 更新最大岛屿面积 result = Math.max(result, count) } } } console.log(result); })()

这些题都是思路比较简单,难点都在dfs和bfs的理论基础上

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 22:16:46

3步快速掌握Scratch项目打包:用TurboWarp让作品独立运行

3步快速掌握Scratch项目打包&#xff1a;用TurboWarp让作品独立运行 【免费下载链接】packager Converts Scratch projects into HTML files, zip archives, or executable programs for Windows, macOS, and Linux. 项目地址: https://gitcode.com/gh_mirrors/pack/packager…

作者头像 李华
网站建设 2026/9/3 1:00:50

如何快速掌握Power BI主题模板:从新手到专家的完整指南

如何快速掌握Power BI主题模板&#xff1a;从新手到专家的完整指南 【免费下载链接】PowerBI-ThemeTemplates JSON Templates for assembling Power BI Themes 项目地址: https://gitcode.com/gh_mirrors/pow/PowerBI-ThemeTemplates 在数据可视化的世界里&#xff0c;P…

作者头像 李华
网站建设 2026/8/30 7:58:39

PaddlePaddle在智能客服中的应用:NLP模型+GPU实时响应

PaddlePaddle在智能客服中的应用&#xff1a;NLP模型GPU实时响应 在客户服务领域&#xff0c;用户对“秒回”的期待早已成为常态。无论是电商平台的订单咨询&#xff0c;还是金融App的账单疑问&#xff0c;延迟超过几秒钟的响应就可能引发不满。而传统智能客服常因理解不准、反…

作者头像 李华
网站建设 2026/9/2 23:06:22

Wireshark DNS协议分析终极指南:从基础到高级排查

Wireshark DNS协议分析终极指南&#xff1a;从基础到高级排查 【免费下载链接】wireshark Read-only mirror of Wiresharks Git repository at https://gitlab.com/wireshark/wireshark. ⚠️ GitHub wont let us disable pull requests. ⚠️ THEY WILL BE IGNORED HERE ⚠️ …

作者头像 李华
网站建设 2026/8/29 11:18:26

15、网站技术优化与内容创作全攻略

网站技术优化与内容创作全攻略 1. 网站配置菜单中的关键设置 在网站配置菜单里,有两个重要设置值得关注,即“抓取速率”和“参数处理”。 - 抓取速率 :默认情况下,抓取速率由谷歌自动确定。但如果你希望谷歌更慢地抓取你的网站,可以自定义该速率。不过,只有当服务器…

作者头像 李华
网站建设 2026/9/2 23:58:29

17、网站内容架构、写作与链接建设全攻略

网站内容架构、写作与链接建设全攻略 1. 内容架构:分类与标签的运用 为网站内容设置合理的结构,不仅方便访客找到所需信息,还能助力搜索引擎发现和索引内容。在 WordPress 中,分类和标签虽都可用于组织内容,但二者有所不同。 分类能将网站按层次结构划分成不同部分,用户…

作者头像 李华