代码随想录D50-51 图论 Python
理论基础
理论基础部分依然沿用代码随想录教程中的介绍:
图的种类



度

连通性
连通性用于表示图中节点的连通情况。

如果有节点不能到达其他节点,则为非连通图,想象将多个水分子表示为图,不考虑非键作用,这张图就不是连通图。

强连通图的概念只针对有向图,因为有向图边的方向也会影响各个节点之间的连通性。

无向图中 节点3 、节点4 构成的子图不是该无向图的联通分量。因为必须是极大联通子图才能是连通分量,所以 必须是节点3、节点4、节点6 构成的子图才是连通分量。 
图的构造
- 邻接矩阵 使用 二维数组来表示图结构。 邻接矩阵是从节点的角度来表示图,有多少节点就申请多大的二维数组。
邻接矩阵的优点:
-
表达方式简单,易于理解
-
检查任意两个顶点间是否存在边的操作非常快
-
适合稠密图,在边数接近顶点数平方的图中,邻接矩阵是一种空间效率较高的表示方法。
缺点:
-
遇到稀疏图,会导致申请过大的二维数组造成空间浪费 且遍历 边 的时候需要遍历整个n * n矩阵,造成时间浪费
- 邻接表 使用 数组 + 链表的方式来表示。 邻接表是从边的数量来表示图,有多少边 才会申请对应大小的链表。

邻接表的优点:
-
对于稀疏图的存储,只需要存储边,空间利用率高
-
遍历节点连接情况相对容易
缺点:
-
检查任意两个节点间是否存在边,效率相对低,需要 O(V)时间,V表示某节点连接其他节点的数量。
-
实现相对复杂,不易理解
图的遍历方式
图的遍历方式基本是两大类:
-
深度优先搜索(dfs)
-
广度优先搜索(bfs)
在讲解二叉树章节的时候,其实就已经讲过这两种遍历方式。
二叉树的递归遍历,是dfs 在二叉树上的遍历方式。
二叉树的层序遍历,是bfs 在二叉树上的遍历方式。
深度优先搜索理论基础 重要!
对比bfs(广度优先搜索来说):
-
dfs是指定一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,再换方向(换方向的过程就涉及到了回溯),回到上一个节点,然后继续。
-
bfs是先把本节点所连接的所有节点遍历一遍,走到下一个节点的时候,再把连接节点的所有节点遍历一遍,搜索方向更像是广度,四面八方的搜索过程。
因此我们可以发现,深搜和广搜在图结构上是有一个范式框架的,首先学习深搜框架:
深度优先搜索的本质是回溯算法,回溯就涉及到递归。因此可以使用递归框架:
1. 确认递归函数,确认传入参数
2. 确认函数终止条件
3. 图中涉及到节点出发路径,因此要额外加上路径
98. 所有可达路径


要点:
找到从1到n的所有路径,图遍历方法的考察。输入第一行为节点数和边数量,之后为边索引。
解法:
1. 确认递归函数,参数
首先我们dfs函数一定要存一个图,用来遍历的,需要存一个目前我们遍历的节点,定义为x。
还需要存一个n,表示终点,我们遍历的时候,用来判断当 x==n 时候 标明找到了终点。
2. 确认终止条件
当目前遍历的节点 为 最后一个节点 n 的时候 就找到了 一条 从出发点到终止点的路径。
3. 处理目前搜索节点出发的路径
接下来是走,当前遍历节点x的下一个节点。这个步骤的逻辑如下:
首先 是要找到 x节点指向了哪些节点。
然后 选中的x所指向的节点,加入到单一路径来。
最后 进入下一层递归
实现:
def dfs(graph, x, n, path, result):if x == n:## 一定要注意使用copy 保证过程中所有路径的记录result.append(path.copy())returnfor i in range(1, n + 1):if graph[x][i] == 1:# 判断边之后将节点路径加入path.append(i)# 递归继续深度搜索dfs(graph, i, n, path, result)# 退出dfs说明当前路径结束 回溯path.pop()def main():n, m = map(int, input().split())## 方便直接对应节点graph = [[0] * (n + 1) for _ in range(n + 1)]for i in range(m):s, t = map(int, input().split())graph[s][t] = 1 result = []## 启动深度优先搜索dfs(graph, x=1, n=n, path=[1], result=result)if not result:print(-1)else:## 注意输出格式for path in result:print((' ').join(map(str, path)))if __name__ == "__main__":main()
广度优先搜索理论基础 重要!
广搜的搜索方式就适合于解决两个点之间的最短路径问题。
因为广搜是从起点出发,以起始点为中心一圈一圈进行搜索,一旦遇到终点,记录之前走过的节点就是一条最短路。
当然,也有一些问题是广搜 和 深搜都可以解决的,例如岛屿问题,这类问题的特征就是不涉及具体的遍历方式,只要能把相邻且相同属性的节点标记上就行。
BFS是一圈一圈的搜索过程,我们用一个方格地图,假如每次搜索的方向为 上下左右(不包含斜上方),那么给出一个start起始位置,那么BFS就是从四个方向走出第一步。
搜索的直观过程如下:


在广度优先搜索中,即使有障碍,搜索也是能够继续执行的。
99. 岛屿数量 广度优先

要点:
遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都标记上。
在广度搜索函数中,我们需要指定一个优先队列deque,以保证搜索可以逐层进行。
同时,考虑搜索的剪枝,我们需要在搜索过程中严谨地维护已访问节点,以及判断可以遍历的合法节点。
实现:
from collections import dequedirections = [[0, 1], [1, 0], [-1, 0], [0, -1]]def bfs(graph, visit, x, y):## 初始化一个队列 执行先进先出que = deque([])## 将当前传入节点加入队列que.append([x, y])## 只要计算了节点 就先记录visit防止重复visit[x][y] = Truewhile que:cur_x, cur_y = que.popleft()## 遍历四个方向上的所有节点 每个节点遍历完就加入队列 等待下一层for i, j in directions:next_x, next_y = cur_x + i, cur_y + j## 排除不合法节点if next_y < 0 or next_x < 0 or next_x >= len(graph) or next_y >= len(graph[0]):continue## 将之前没有访问的节点进行记录 标记visit if not visit[next_x][next_y] and graph[next_x][next_y] == 1:visit[next_x][next_y] = True## 同时将该节点加入队列 进入下一层遍历que.append([next_x, next_y])def main():n, m = map(int, input().split())graph = []## 初始化节点分布for i in range(n):graph.append(list(map(int, input().split())))visit = [[False] * m for _ in range(n)]res = 0## 逐个节点遍历 每次执行广度优先 直到队列元素周围没有岛屿for i in range(n):for j in range(m):if graph[i][j] == 1 and not visit[i][j]:res += 1bfs(graph, visit, i, j)print(res)if __name__ == '__main__':main()
99. 岛屿数量 深度优先
要点:
对于节点的访问而不是路径的访问,深搜的关联条件会多一些:
1. 确认递归函数,参数
递归函数对节点的四个方向进行遍历,如果存在符合要求的节点,就一直遍历直到一次深搜终止。此时无需pop,因为不用记录路径。回到四个方向的循环中会自动开始下一个方向的遍历,以此找完全部数值为1的节点。
2. 确认终止条件
当前节点的值为0,或者已经被遍历过,则终止并回退。
3. 处理目前搜索节点出发的路径
在外层首先做一个对所有节点的遍历,保证代入递归的节点符合岛屿+未访问的要求。一旦进入递归,就意味着我们来到了一个新的岛屿。
实现:
directions = [[0, 1], [1, 0], [-1, 0], [0, -1]]def dfs(graph, visit, x, y):## 没有岛屿或下一个节点已经被访问if graph[x][y] == 0 or visit[x][y]:return## 记录当前访问的节点visit[x][y] = True## 根据方向访问下一个节点for i, j in directions:next_x, next_y = x + i, y + j # 排除不合法节点if next_x < 0 or next_x >= len(graph) or next_y < 0 or next_y >= len(graph[0]):continue## 执行深度优先搜索dfs(graph, visit, next_x, next_y)def main():n, m = map(int, input().split())graph = []## 初始化节点分布for i in range(n):graph.append(list(map(int, input().split())))res = 0visit = [[False] * m for _ in range(n)]for i in range(n):for j in range(m):## 深搜递归退出回到循环时意味着上一个岛屿一定被遍历完了if graph[i][j] == 1 and not visit[i][j]:res += 1 dfs(graph, visit, i, j)print(res)
99. 岛屿的最大面积 深度优先

要点:
本题需要比对不同岛屿之间的最大面积,言外之意就是要记录遍历过的岛屿,使用深度优先搜索时可以在dfs内部计数,更简便的技巧是定义全局变量,无参实现主函数和dfs的传递。
实现:
directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]def dfs(graph, visit, x, y):global resultif graph[x][y] == 0 or visit[x][y]:returnvisit[x][y] = True # 先标记为访问过result += 1 # 计数for i, j in directions:next_x, next_y = x + i, y + j if next_x < 0 or next_x >= len(graph) or next_y < 0 or next_y >= len(graph[0]):continuedfs(graph, visit, next_x, next_y) # 使用next_x和next_y进行递归调用def main():global resultn, m = map(int, input().split())graph = []for i in range(n):graph.append(list(map(int, input().split())))max_res = 0visit = [[False] * m for _ in range(n)]for i in range(n):for j in range(m):if graph[i][j] == 1 and not visit[i][j]:result = 0 # 初始化为0dfs(graph, visit, i, j)max_res = max(max_res, result)print(max_res)if __name__ == "__main__":main()
99. 岛屿的最大面积 广度优先
要点:
广度优先搜索仍然遵循层级关系,使用deque记录层次;在每次遍历到新的节点时记录即可。
实现:
from collections import dequedirections = [[0, 1], [1, 0], [0, -1], [-1, 0]]def bfs(graph, visit, x, y):result = 1que = deque([])que.append([x, y])visit[x][y] = Truewhile que:cur_x, cur_y = que.popleft()for i, j in directions:next_x, next_y = cur_x + i, cur_y + j if next_x < 0 or next_x >= len(graph) or next_y < 0 or next_y >= len(graph[0]):continueif not visit[next_x][next_y] and graph[next_x][next_y] == 1:visit[next_x][next_y] = Trueque.append([next_x, next_y])result += 1return resultdef main():n, m = map(int, input().split())graph = []for i in range(n):graph.append(list(map(int, input().split())))max_res = 0visit = [[False] * m for _ in range(n)]for i in range(n):for j in range(m):if graph[i][j] == 1 and not visit[i][j]:result = bfs(graph, visit, i, j)max_res = max(max_res, result)print(max_res)
相关文章:
代码随想录D50-51 图论 Python
理论基础 理论基础部分依然沿用代码随想录教程中的介绍: 图的种类 度 连通性 连通性用于表示图中节点的连通情况。 如果有节点不能到达其他节点,则为非连通图,想象将多个水分子表示为图,不考虑非键作用,这张图就不是…...
【八股】计算机网络
HTTP 应用层网络层传输层接口层数据链路层 HTTP基本概念 HTTP是什么? HTTP是超文本传输协议 HTTP 常见的状态码有哪些? 200、204、206 成功 301、302、304 重定向 400、403、404 客户端错误 500、501、502、503 服务端错误...
在 Spring Boot 中使用 `@Autowired` 和 `@Bean` 注解
文章目录 在 Spring Boot 中使用 Autowired 和 Bean 注解示例背景 1. 定义 Student 类2. 配置类:初始化 Bean3. 测试类:使用 Autowired 注解自动注入 Bean4. Spring Boot 的自动装配5. 总结 在 Spring Boot 中使用 Autowired 和 Bean 注解 在 Spring Bo…...
Qt 保留小数点 固定长度 QString 格式化
QString的arg()函数格式化输出double类型数值,包括fieldWidth、fmt、prec和fillChar参数的作用。示例代码展示了如何设置精度和填充字符,以及字段宽度的影响。文中提到,当fieldWidth小于实际长度时,前面的填充不会被截断。此外&am…...
Mac M3/M4 本地部署Deepseek并集成vscode
Mac 部署 使用傻瓜集成平台ollama,ollama平台依赖于docker,Mac的M3/M4 因doesn’t have VT-X/AMD-v enabled 所以VB,VM无法使用,导致docker无法启动,需要使用docker的替代品podman, 它完全兼容docker brew install p…...
TikTok账户安全指南:如何取消两步验证?
TikTok账户安全指南:如何取消两步验证? 在这个数字化的时代,保护我们的在线账户安全变得尤为重要。TikTok,作为全球流行的社交媒体平台,其账户安全更是不容忽视。两步验证作为一种增强账户安全性的措施,虽…...
【C++复习专题】—— 类和对象,包含类的引入、访问限定符、类的6个默认成员函数等
1.类的定义 class classname {//类体:由成员函数和成员变量组成 }; class为定义类的关键字,classname为类的名字,{}中为类的主体。 类体中的内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方…...
Spring--BeanDefinition的用法
原文网址:Spring--BeanDefinition的用法_IT利刃出鞘的博客-CSDN博客 简介 本文介绍BeanDefinition的用法。 BeanDefinition是Bean的信息,用于生成Bean。 示例:手动注册Bean 待填充 BeanDefinition的作用 get 下图是通过beanDefinitio…...
关于C#的一些基础知识点汇总
1.C#结构体可以继承接口吗?会不会产生GC? 在 C# 中,结构体不能继承类,但可以实现接口。 代码: interface IMyInterface {void MyMethod(); }struct MyStruct : IMyInterface {public void MyMethod(){Console.Write…...
一文讲解Redis为什么读写性能高以及I/O复用相关知识点
Redis为什么读写性能高呢? Redis 的速度⾮常快,单机的 Redis 就可以⽀撑每秒十几万的并发,性能是 MySQL 的⼏⼗倍。原因主要有⼏点: ①、基于内存的数据存储,Redis 将数据存储在内存当中,使得数据的读写操…...
Hadoop-HA(高可用)机制
首先:在每个NAMENODE上都会有一个zkfc(zookeeper failover colltroller) ,负责这两个的状态管理。哪个是(active和standby)然后写入zk集群里面。同时监控自己所在的机器是否正常。一旦active上zkfc的发现异…...
51单片机-按键
1、独立按键 1.1、按键介绍 轻触开关是一种电子开关,使用时,轻轻按开关按钮就可使开关接通,当松开手时,开关断开。 1.2、独立按键原理 按键在闭合和断开时,触点会存在抖动现象。P2\P3\P1都是准双向IO口,…...
深度学习的力量:精准肿瘤检测从此不再遥远
目录 引言 一、医学图像分析的挑战与深度学习的优势 1.1 医学图像分析的挑战 1.2 深度学习的优势 二、肿瘤检测的深度学习模型设计 2.1 卷积神经网络(CNN)的基本原理 2.2 网络架构设计 2.3 模型训练 三、肿瘤检测中的挑战与解决方案 3.1 数据不…...
初尝git自结命令大全与需要理解的地方记录
常用命令 git init–初始化工作区touch 文件全称–在工作区创建文档rm 文件全称 --删除文档notepad 文件全称–在工作区打开文档cat 文件全称–在显示框显示文档的东西git status --显示工作区的文件冲突的文件 (git add 文件全称或者.) —将工作区文件…...
LangChain 技术入门指南:探索语言模型的无限可能
在当今的技术领域,LangChain 正逐渐崭露头角,成为开发语言模型应用的强大工具。如果你渴望深入了解并掌握这一技术,那么就跟随本文一起开启 LangChain 的入门之旅吧! (后续将持续输出关于LangChain的技术文章,有兴趣的同学可以关注…...
Nginx WebSocket 长连接及数据容量配置
WebSocket 协议是实现实时通信的关键技术。相比于传统的 HTTP 请求-响应模式,WebSocket 提供了双向、持久化的通信方式。Nginx 作为一个高性能的反向代理服务器,可以非常有效地处理 WebSocket 连接,但要正确处理 WebSocket 长连接和传输大数据…...
Pycharm+CodeGPT+Ollama+Deepseek
首先,体验截图: 接着: 1、下载Ollama: Download Ollama on macOS 2、下载模型 以1.5b为例,打开命令行,输入: ollama run deepseek-r1:1.5b 3、Pycharm安装Code GPT插件 打开PyCharm,找到文…...
k8s Container runtime network not ready
问题 k8s 3 控制节点,docker 运行时,后期踢掉其中一个节点,使用了 containerd 运行时,但是在加入集群的时候,node 状态 notready。查看 kubelet 的日志发现如下报错 Feb 20 11:28:14 bjm3 kubelet[144781]: E0220 11:28:14.506374 144781 kubelet.go:2475] "Conta…...
阿里云k8s服务部署操作一指禅
文章目录 DockerFile镜像操作阿里云k8s服务部署 DockerFile # 使用 JDK 17 官方镜像 # linux架构:FROM --platformlinux/amd64 openjdk:17-jdk-slim # arm架构:openjdk:17-jdk-slim FROM --platformlinux/amd64 openjdk:17-jdk-slim# 设置工作目录 WORK…...
pdf-extract-kit paddle paddleocr pdf2markdown.py(效果不佳)
GitHub - opendatalab/PDF-Extract-Kit: A Comprehensive Toolkit for High-Quality PDF Content Extraction https://github.com/opendatalab/PDF-Extract-Kit pdf2markdown.py 运行遇到的问题: 错误: -------------------------------------- C Tra…...
.NET + Vue3 的前后端项目在IIS的发布
目录 一、发布准备 1、安装 IIS 2、安装 Windows Hosting Bundle(.NET Core 托管捆绑包) 3、安装 IIS URL Rewrite 二、项目发布 1、后端项目发布 2、前端项目发布 3、将项目部署到 IIS中 三、网站配置 1、IP配置 2、防火墙配置 3、跨域配置…...
交互编程工具之——Jupyter
Jupyter 是什么? Jupyter 是一个开源的交互式编程和数据分析工具,广泛应用于数据科学、机器学习、教育和研究领域。其核心是 Jupyter Notebook(现升级为 JupyterLab),允许用户在一个基于浏览器的界面中编写代码、运行…...
微信小程序客服消息接收不到微信的回调
微信小程序客服消息,可以接收到用户进入会话事件的回调,但是接收不到用户发送消息的回调接口。需要在微信公众平台,把转发消息给客服的开关关闭。需要把这个开关关闭,否则消息会直接发送给设置的客服,并不会走设置的回…...
easyexcel 2.2.6版本导出excel模板时,标题带下拉框及其下拉值过多不显示问题
需求背景:有一个需求要做下拉框的值有100多条,同时这个excel是一个多sheet的导入模板 直接用easyexcel 导出,会出现下拉框的值过多,导致生成出来的excel模板无法正常展示下拉功能 使用的easyexcel版本:<depende…...
影视大数据分析新范式:亮数据动态代理驱动的实时数据采集方案
一、项目背景与挑战 在数据驱动决策的时代,影视数据分析对内容平台至关重要。但豆瓣等平台设有: 高频请求IP封禁机制User-Agent指纹检测请求频率阈值控制验证码验证系统 传统爬虫方案面临: 单一IP存活时间<5分钟采集成功率<30%数据更新…...
免费体验,在阿里云平台零门槛调用满血版DeepSeek-R1模型
一、引言 随着人工智能技术的飞速发展,各类AI模型层出不穷。其中,DeepSeek作为一款新兴的推理模型,凭借其强大的技术实力和广泛的应用场景,逐渐在市场中崭露头角。本文将基于阿里云提供的零门槛解决方案,对DeepSeek模…...
ok113i平台——多媒体播放器适配
1. 视频播放支持 1.1 在Linux平台交叉编译ffmpeg动态库,详情查看《ok113i平台——交叉编译音视频动态库》 提取如下动态库: libavcodec.so.58.134.100 libavdevice.so.58.13.100 libavfilter.so.7.110.100 libavformat.so.58.76.100 libavutil.so.56.…...
使用Python中的`gensim`库构建LDA(Latent Dirichlet Allocation)模型来分析收集到的评论
下面为你详细介绍如何使用Python中的gensim库构建LDA(Latent Dirichlet Allocation)模型来分析收集到的评论。LDA是一种主题模型,它可以将文档集合中的文本按照主题进行分类。 步骤概述 数据预处理:对收集到的评论进行清洗、分词…...
23种设计模式 - 策略模式
模式定义 策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列可互换的算法,并将每个算法封装成独立类,使得算法可以独立于客户端变化。该模式的核心思想是解耦算法的定义与使用,适用于需要动…...
Cursor 与团队协作:提升团队开发效率
引言 在团队开发中,代码质量参差不齐、重复错误频发、代码审查耗时过长是制约效率的三大痛点。据 GitHub 调查,开发者平均每周花费 4.3 小时修复他人代码问题,而 60% 的合并请求(PR)因风格或低级错误被驳回。Cursor 作…...
