代码随想录算法训练营第五十一天 | 99.岛屿数量-深搜 ,99.岛屿数量-广搜 ,100.岛屿的最大面积

news2025/3/15 0:37:21

目录

99.岛屿数量-深搜

思路

方法一: 深度优先搜索-先判断

方法二:深度优先搜索-终止条件

心得收获 

99.岛屿数量-广搜 

思路

广度优先搜索

方法一:广度优先搜索

100.岛屿的最大面积

思路

深度优先搜索

广度优先搜索

方法一:深度优先搜索

方法二:广度优先搜索

心得收获


99.岛屿数量-深搜

  • 题目链接:卡码网题目链接(ACM模式)
  • 文章讲解:代码随想录 

题目描述:

给定一个由 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,BFS或者并查集。

方法一: 深度优先搜索-先判断

direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 四个方向:上、右、下、左


def dfs(grid, visited, x, y):
    """
    对一块陆地进行深度优先遍历并标记
    """
    for i, j in direction:
        next_x = x + i
        next_y = y + j
        # 下标越界,跳过
        if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):
            continue
        # 未访问的陆地,标记并调用深度优先搜索
        if not visited[next_x][next_y] and grid[next_x][next_y] == 1:
            visited[next_x][next_y] = True
            dfs(grid, visited, next_x, next_y)


if __name__ == '__main__':  
    # 版本一
    n, m = map(int, input().split())
    
    # 邻接矩阵
    grid = []
    for i in range(n):
        grid.append(list(map(int, input().split())))
    
    # 访问表
    visited = [[False] * m for _ in range(n)]
    
    res = 0
    for i in range(n):
        for j in range(m):
            # 判断:如果当前节点是陆地,res+1并标记访问该节点,使用深度搜索标记相邻陆地。
            if grid[i][j] == 1 and not visited[i][j]:
                res += 1
                visited[i][j] = True
                dfs(grid, visited, i, j)
    
    print(res)

方法二:深度优先搜索-终止条件

direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 四个方向:上、右、下、左


def dfs(grid, visited, x, y):
    """
    对一块陆地进行深度优先遍历并标记
    """
    # 与版本一的差别,在调用前增加判断终止条件
    if visited[x][y] or grid[x][y] == 0:
        return
    visited[x][y] = True

    for i, j in direction:
        next_x = x + i
        next_y = y + j
        # 下标越界,跳过
        if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):
            continue
        # 由于判断条件放在了方法首部,此处直接调用dfs方法
        dfs(grid, visited, next_x, next_y)


if __name__ == '__main__':
    # 版本二
    n, m = map(int, input().split())

    # 邻接矩阵
    grid = []
    for i in range(n):
        grid.append(list(map(int, input().split())))

    # 访问表
    visited = [[False] * m for _ in range(n)]

    res = 0
    for i in range(n):
        for j in range(m):
            # 判断:如果当前节点是陆地,res+1并标记访问该节点,使用深度搜索标记相邻陆地。
            if grid[i][j] == 1 and not visited[i][j]:
                res += 1
                dfs(grid, visited, i, j)

    print(res)

心得收获 

为什么 以上方法一代码中的dfs函数,没有终止条件呢? 感觉递归没有终止很危险。

其实终止条件 就写在了 调用dfs的地方,如果遇到不合法的方向,直接不会去调用dfs。

这里大家应该能看出区别了,无疑就是版本一中 调用dfs 的条件判断 放在了 版本二 的 终止条件位置上。

版本一的写法是 :下一个节点是否能合法已经判断完了,传进dfs函数的就是合法节点。

版本二的写法是:不管节点是否合法,上来就dfs,然后在终止条件的地方进行判断,不合法再return。

理论上来讲,版本一的效率更高一些,因为避免了 没有意义的递归调用,在调用dfs之前,就做合法性判断。 但从写法来说,可能版本二 更利于理解一些。

99.岛屿数量-广搜 

  • 题目链接:卡码网题目链接(ACM模式)
  • 文章讲解:代码随想录 

给定一个由 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

思路

广度优先搜索

如果不熟悉广搜,建议先看 广搜理论基础。

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

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

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

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

图二

方法一:广度优先搜索

def dfs(grid, visited, x, y):
    dir = [(0, 1), (1, 0), (-1, 0), (0, -1)]  # 四个方向
    for d in dir:
        nextx, nexty = x + d[0], y + d[1]
        if 0 <= nextx < len(grid) and 0 <= nexty < len(grid[0]):
            if not visited[nextx][nexty] and grid[nextx][nexty] == 1:  # 没有访问过的 同时 是陆地的
                visited[nextx][nexty] = True
                dfs(grid, visited, nextx, nexty)

def main():
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(n)]
    visited = [[False] * m for _ in range(n)]

    result = 0
    for i in range(n):
        for j in range(m):
            if not visited[i][j] and grid[i][j] == 1:
                visited[i][j] = True
                result += 1  # 遇到没访问过的陆地,+1
                dfs(grid, visited, i, j)  # 将与其链接的陆地都标记上 True

    print(result)

if __name__ == "__main__":
    main()

100.岛屿的最大面积

  • 题目链接:卡码网题目链接(ACM模式)
  • 文章讲解:代码随想录 

给定一个由 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其实也是凭感觉来的,有的时候dfs函数中写终止条件才能过,有的时候 dfs函数不写终止添加也能过!

这里其实涉及到dfs的两种写法。

写法一,dfs只处理下一个节点,即在主函数遇到岛屿就计数为1,dfs处理接下来的相邻陆地

写法二,dfs处理当前节点,即在主函数遇到岛屿就计数为0,dfs处理接下来的全部陆地

广度优先搜索

关于广度优先搜索,如果大家还不了解的话,看这里:广度优先搜索精讲

 

方法一:深度优先搜索

# 四个方向
position = [[0, 1], [1, 0], [0, -1], [-1, 0]]
count = 0


def dfs(grid, visited, x, y):
    """
    深度优先搜索,对一整块陆地进行标记
    """
    global count  # 定义全局变量,便于传递count值
    for i, j in position:
        cur_x = x + i
        cur_y = y + j
        # 下标越界,跳过
        if cur_x < 0 or cur_x >= len(grid) or cur_y < 0 or cur_y >= len(grid[0]):
            continue
        if not visited[cur_x][cur_y] and grid[cur_x][cur_y] == 1:
            visited[cur_x][cur_y] = True
            count += 1
            dfs(grid, visited, cur_x, cur_y)


n, m = map(int, input().split())
# 邻接矩阵
grid = []
for i in range(n):
    grid.append(list(map(int, input().split())))
# 访问表
visited = [[False] * m for _ in range(n)]

result = 0  # 记录最终结果
for i in range(n):
    for j in range(m):
        if grid[i][j] == 1 and not visited[i][j]:
            count = 1
            visited[i][j] = True
            dfs(grid, visited, i, j)
            result = max(count, result)

print(result)

方法二:广度优先搜索

from collections import deque

position = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 四个方向
count = 0


def bfs(grid, visited, x, y):
    """
    广度优先搜索对陆地进行标记
    """
    global count  # 声明全局变量
    que = deque()
    que.append([x, y])
    while que:
        cur_x, cur_y = que.popleft()
        for i, j in position:
            next_x = cur_x + i
            next_y = cur_y + j
            # 下标越界,跳过
            if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):
                continue
            if grid[next_x][next_y] == 1 and not visited[next_x][next_y]:
                visited[next_x][next_y] = True
                count += 1
                que.append([next_x, next_y])


n, m = map(int, input().split())
# 邻接矩阵
grid = []
for i in range(n):
    grid.append(list(map(int, input().split())))
visited = [[False] * m for _ in range(n)]  # 访问表

result = 0  # 记录最终结果
for i in range(n):
    for j in range(m):
        if grid[i][j] == 1 and not visited[i][j]:
            count = 1
            visited[i][j] = True
            bfs(grid, visited, i, j)
            res = max(result, count)

print(result)

心得收获

其实本题和岛屿数量这道题思路基本上是一致的,只不过需要计算每个陆地的面积,求最大

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

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

相关文章

c语言——用一维数组输出杨辉三角形

一.代码 #include <stdio.h> int Num[100]; int Hang; int Lie; int a; int Flag; int main() {Lie 1;Hang 1;a 0;while (1) {//列1为1if (Lie 1) {Num[1] 1;Lie;}//数据存到数组里面while (Hang > Lie && Hang ! 2) { if (Hang!Lie) {Flag Num[Lie] …

解锁Web3.0——Scaffold-eth打造以太坊DApp的终极指南

&#x1f680;本系列文章为个人学习笔记&#xff0c;目的是巩固知识并记录我的学习过程及理解。文笔和排版可能拙劣&#xff0c;望见谅。 目录 前言 一、快速部署 1、前期准备&#xff1a; 2、安装项目&#xff1a; ​ 二、配置部署运行环境 1、初始化本地链&#xff1a;…

Qt-QWidget的windowOpacity属性(16)

目录 描述 相关API 使用 设置槽函数 两个问题 第一个问题&#xff1a;浮点数精确度问题 第二个问题&#xff1a;防御性编程 描述 这个属性就是用来设置窗口的不透明度的 相关API 使用 我们创建一个新的项目来进行测试 如下&#xff0c;我们再把这两个按钮设置一下名…

改进YOLOv8系列:加入多尺度卷积注意力MSCA注意力: ,即插即用,助力小目标检测

改进YOLOv8系列:加入非对称卷积块ACNet,加强CNN 的内核骨架 论文研究概括MSCA模块介绍需要修改的代码MSCA代码创建yaml文件测试是否创建成功本文提供了改进 YOLOv8注意力系列包含不同的注意力机制以及多种加入方式,在本文中具有完整的代码和包含多种更有效加入YOLOv8中的ya…

模型 跃迁(泛化)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。跨越式变革与发展。 1 跃迁的应用 1.1 个人成长中的跃迁现象&#xff1a;职业转型与技能升级 背景描述&#xff1a; 在个人职业发展的过程中&#xff0c;跃迁现象指的是个体在技能、知识和职业地位上…

Python教程(二十一) : 从零开始制作计算器应用【PyQt6】

文章目录 专栏列表环境准备代码解析主要组件初始化界面布局设置事件处理计算逻辑 运行应用完整代码示例截图总结注意 专栏列表 Python教程&#xff08;十&#xff09;&#xff1a;面向对象编程&#xff08;OOP&#xff09;Python教程&#xff08;十一&#xff09;&#xff1a;…

国产化软件内容及要求

国产化软件是指在中国自主研发的软件产品&#xff0c;旨在减少对外部技术的依赖&#xff0c;提升国家信息安全和软件产业的自主可控能力。国产化软件涵盖了从操作系统、数据库、办公软件、各类应用软件、中间件等多个层面。 操作系统&#xff1a;国产操作系统如银河麒麟、UOS、…

博客建站8 - 选择hexo博客网站的主题

1. 环境说明2. 体验过的hexo站点主题 2.1. Acorn2.2. hexo-theme-cafe2.3. volantis2.4. NexT 3. 参考文档 1. 环境说明 博客框架&#xff1a; Hexo网站主题&#xff1a; Volantis评论系统&#xff1a; Disqus服务器: 阿里云ECS服务器系统&#xff1a; Ubuntu 24.04 LTS 2. …

仕考网:结构化面试流程介绍

(一)结构化面试 结构化面试&#xff0c;也叫做标准化面试&#xff0c;考官按照预先设定好的一套试题以问答方式与应试者当面交谈&#xff0c;根据应试者的言语、行为表现&#xff0c;对其相关能力和个性特征作出相应评价。 &#xff08;二&#xff09;考试流程 抵达考场——…

CAD 多个页面在一个任务栏图标设置

命令行输入快捷键op或&#xff1a; 下图打对号&#xff0c;确定即可。

vsCode 自动发布文件到服务器文件

1.新建 publish.cmd文件 xcopy D:\_____\*.* \\_____\jyou /s /e /y源文件夹和目标文件夹按照自己替换&#xff0c;/s /e /y会复制空白文件夹&#xff0c;且遇到相同文件直接覆盖 2.将这个文件复制到nodemodules/bin目录下 3.在package.json中配置发布命令

翻译器大分享,这5款你选哪款?

作为一个经常需要阅读和翻译各种学术论文和专业文档的研究生&#xff0c;我深知找到一款好用的翻译工具是多么重要。今天&#xff0c;我就来跟大家聊聊我用过的四款翻译PDF文档的工具它们的表现如何呢&#xff1f;一起来看看吧&#xff01; 一、福昕在线翻译 网址&#xff1a;…

[米联客-XILINX-H3_CZ08_7100] FPGA程序设计基础实验连载-38 LVDS Select IO高速Serdes

软件版本&#xff1a;VIVADO2021.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA 实验平台&#xff1a;米联客-MLK-H3-CZ08-7100开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http…

使用 VisionTransformer(VIT) FineTune 训练驾驶员行为状态识别模型

一、VisionTransformer(VIT) 介绍 大模型已经成为人工智能领域的热门话题。在这股热潮中&#xff0c;大模型的核心结构 Transformer 也再次脱颖而出证明了其强大的能力和广泛的应用前景。Transformer 自 2017年由Google提出以来&#xff0c;便在NLP领域掀起了一场革命。相较于…

Typora 画图技巧(思维利器,含文本及图示~!)

Typora 画图技巧&#xff08;思维利器&#xff0c;含文本及图示~&#xff01;&#xff09; 设置图表示例流程图横向流程图竖向流程图标准流程图标准流程图&#xff08;横向&#xff09; UML时序图UML时序图一UML时序图二UML标准时序图一UML标准时序图二 甘特图类图状态图饼图 &…

找高清视频素材,上这8个网站

分享8个提供高清视频素材的优秀网站&#xff0c;无论你是在制作宣传片、社交媒体内容还是影视作品&#xff0c;这些资源都能帮助你找到理想的素材&#xff0c;让你的作品更加生动和引人注目。 1、菜鸟图库 视频素材下载_mp4视频大全 - 菜鸟图库 菜鸟图库免费视频素材下载。网站…

UWB定位室外基站

定位基站&#xff0c;型号SW&#xff0c;是一款基于无线脉冲技术开发的UWB定位基站&#xff0c;基站可用于人员、车辆、物资的精确定位&#xff0c; 该基站专为恶劣环境使用而设计&#xff0c;防尘、防水等级IP67&#xff0c;工业级标准支持365天连续运行&#xff0c;本安防爆可…

Java并发编程实战 05 | 什么是线程组?

1.线程组介绍 在 Java 中&#xff0c;ThreadGroup 用于表示一组线程。通过 ThreadGroup&#xff0c;我们可以批量控制和管理多个线程&#xff0c;使得线程管理更加方便。 ThreadGroup 和 Thread 的关系就像它们的字面意思一样简单&#xff1a;每个线程 (Thread) 必定属于一个线…

7.统一网关-Gateway

文章目录 1.统一网关介绍2.网关开发3.predicate4.Route Predicate Factories(路由断言工厂)4.1Path 路由断言工厂4.2.Method 路由断言工厂4.3 Header 路由断言工厂4.4 Query 路由断言工厂4.5 Host 路由断言工厂4.6 After 路由断言工厂4.7 Before 路由断言工厂4.8 Between 路由断…

FPGA实现串口升级及MultiBoot(二)FPGA启动流程

这个系列开篇肯定要先了解FPGA的启动流程&#xff0c;试想一下&#xff1a;我想实现MultiBoot&#xff0c;那么我应该在什么时候开始升级&#xff0c;升级失败后FPGA进行了哪些操作&#xff0c;以及怎么回到Golden区&#xff1f; 还有一个问题&#xff0c;就是我硬件打板回来&a…