news 2026/4/23 10:55:09

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

作者头像

张小明

前端开发工程师

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/4/18 1:24:50

UnityChess:3D国际象棋游戏开发实战指南

UnityChess&#xff1a;3D国际象棋游戏开发实战指南 【免费下载链接】UnityChess A 3D chess game made with Unity. Core game library submodule: https://github.com/ErkrodC/UnityChessLib 项目地址: https://gitcode.com/gh_mirrors/un/UnityChess UnityChess是一款…

作者头像 李华
网站建设 2026/4/19 16:08:05

PaddlePaddle深度学习平台性能评测:对比TensorFlow与PyTorch

PaddlePaddle深度学习平台性能评测&#xff1a;对比TensorFlow与PyTorch 在AI技术加速落地的今天&#xff0c;一个常被忽视的问题浮出水面&#xff1a;为什么很多企业在选型深度学习框架时&#xff0c;开始从TensorFlow和PyTorch转向PaddlePaddle&#xff1f;尤其在中国市场&am…

作者头像 李华
网站建设 2026/4/17 17:43:58

如何用TurboWarp Packager实现Scratch项目跨平台一键部署

如何用TurboWarp Packager实现Scratch项目跨平台一键部署 【免费下载链接】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/4/21 9:12:40

从零开始掌握Stable Baselines3:强化学习实战全解析

从零开始掌握Stable Baselines3&#xff1a;强化学习实战全解析 【免费下载链接】stable-baselines3 PyTorch version of Stable Baselines, reliable implementations of reinforcement learning algorithms. 项目地址: https://gitcode.com/GitHub_Trending/st/stable-bas…

作者头像 李华
网站建设 2026/4/23 10:21:48

D2RML完整教程:暗黑破坏神2重制版多开工具快速上手

D2RML完整教程&#xff1a;暗黑破坏神2重制版多开工具快速上手 【免费下载链接】D2RML Diablo 2 Resurrected Multilauncher 项目地址: https://gitcode.com/gh_mirrors/d2/D2RML 想要在《暗黑破坏神2&#xff1a;重制版》中同时操控多个角色&#xff0c;体验团队协作的…

作者头像 李华
网站建设 2026/4/18 1:01:16

20、网站链接建设与社交媒体营销全攻略

网站链接建设与社交媒体营销全攻略 在当今数字化的时代,网站的链接建设和社交媒体营销是提升网站知名度和流量的关键要素。下面将详细介绍链接建设的多种方法以及如何利用社交媒体进行有效的推广。 链接建设方法 1. 寻找 dofollow 博客列表 在网上有许多 dofollow 博客列表…

作者头像 李华