练14:DFS基础

欢迎大家订阅【蓝桥杯Python每日一练】 专栏,开启你的 Python数据结构与算法 学习之旅!

文章目录

  • 1 DFS基础
  • 2 n重循环(嵌套循环)
  • 3 DFS与n重循环的区别与联系
  • 4 例题分析


1 DFS基础

①定义
深度优先搜索(DFS,Depth First Search)是一种用于遍历或搜索树或图的算法。

它从根节点开始,尽可能深入每个分支的节点,直到到达叶节点或没有可遍历的节点为止。如果当前节点没有未被访问的邻接节点,DFS会回溯到最近的一个节点,继续遍历未访问的邻接节点。

②基本思想

  • 从起始节点出发,沿着一条路径尽可能深入
  • 如果到达了一个节点,该节点没有未访问的邻接节点(即所有的路径都已遍历完),那么回溯到上一个节点,继续查找其他未访问的邻接节点。
  • 重复这一过程,直到遍历完所有节点

③应用

  • 图遍历:DFS用于图的遍历,尤其适合用来发现图的连接性,查找某一节点,检查是否存在路径等。
  • 树的遍历:DFS可以用来进行树的遍历,包括前序遍历、中序遍历、后序遍历。
  • 拓扑排序:在有向无环图(DAG)中,DFS可以用于生成拓扑排序。
  • 路径搜索:用于在图中寻找从一个节点到另一个节点的路径。
  • 图的连通性:用于检查一个图是否是连通的。

④实现

DFS可以通过递归或者来实现。

a. 递归实现

递归是DFS最自然的实现方式。每次递归调用代表从一个节点开始深度遍历。

def dfs_recursive(graph, node, visited):# 访问当前节点visited.add(node)print(node, end=" ")# 遍历所有邻居节点for neighbor in graph[node]:if neighbor not in visited:dfs_recursive(graph, neighbor, visited)

说明

  • graph是图的邻接表表示,node是当前访问的节点,visited是一个集合,用于记录已访问的节点。
  • 递归地访问每个邻接节点,直到没有未访问的邻接节点为止。

b. 栈实现

如果使用栈来模拟递归,可以避免递归的深度限制,同时保持DFS的深度优先特性。

def dfs_stack(graph, start):visited = set()  # 用于记录已访问的节点stack = [start]  # 用栈来模拟递归while stack:node = stack.pop()if node not in visited:print(node, end=" ")visited.add(node)# 将所有未访问的邻接节点加入栈中for neighbor in reversed(graph[node]):if neighbor not in visited:stack.append(neighbor)

说明

  • 使用栈(stack)来模拟递归的函数调用栈,确保深度优先的遍历。
  • 每次从栈中弹出一个节点并访问,然后将它的未访问邻接节点推入栈中。

⑤图的表示方式

DFS常见的图的表示方式是邻接表,也可以用邻接矩阵来表示。

a. 邻接表表示法

graph = {0: [1, 2],1: [0, 3, 4],2: [0, 5],3: [1],4: [1],5: [2]
}

在邻接表中,graph[node]表示与节点node相邻的所有节点。

b. 邻接矩阵表示法

邻接矩阵是一个二维数组,matrix[i][j] = 1表示节点i和节点j之间有边,matrix[i][j] = 0表示没有边。

# 假设有6个节点,编号为0-5
matrix = [[0, 1, 1, 0, 0, 0],[1, 0, 0, 1, 1, 0],[1, 0, 0, 0, 0, 1],[0, 1, 0, 0, 0, 0],[0, 1, 0, 0, 0, 0],[0, 0, 1, 0, 0, 0]
]

⑥时间复杂度和空间复杂度

a. 时间复杂度

对于一个有V个节点和E条边的图,DFS的时间复杂度是O(V + E)

  • 每个节点最多访问一次。
  • 每条边最多访问一次(在无向图中,边会被两次访问)。

b. 空间复杂度

空间复杂度主要由两个因素决定:

  1. 栈空间:递归时系统调用栈的深度或手动维护的栈的最大深度。最坏情况下是图的节点数V
  2. 已访问节点的存储空间:通常用一个集合或布尔数组来标记已访问节点,占用O(V)空间。

所以,DFS的空间复杂度为O(V)

⑦特点

  • 深度优先:DFS优先深入到图的某一分支,直到无法继续才回溯到上一个节点。
  • 适合路径问题:DFS可以用来寻找从源节点到目标节点的路径(例如,在迷宫中寻找路径)。
  • 可能产生较长的递归链:对于深度较大的图,递归调用栈可能会非常深(可能导致栈溢出)。
  • 不一定找到最短路径:DFS不保证找到从源节点到目标节点的最短路径。对比广度优先搜索(BFS),BFS能够保证找到最短路径。

【示例——DFS遍历图】

假设我们有以下图的邻接表:

graph = {0: [1, 2],1: [0, 3, 4],2: [0, 5],3: [1],4: [1],5: [2]
}

我们从节点0开始进行DFS遍历,递归实现:

visited = set()
dfs_recursive(graph, 0, visited)

输出结果:

0 1 3 4 2 5

从节点0出发,首先访问节点1,然后深入访问节点3,回溯到1,接着访问节点4,然后返回到0,访问节点2,最后访问节点5

2 n重循环(嵌套循环)

①定义
n重循环是指使用多层嵌套的循环结构,常用于需要处理多维数组、多个条件组合或多变量问题的场景。每个循环都是上一层循环的子集,依次遍历。

②核心特点

  • 嵌套:n重循环通常是多层循环结构,每一层循环的次数取决于上一层的循环状态。
  • 复杂度:n重循环的时间复杂度通常是O(n^k)(其中k是循环的层数),适用于解决高维度的遍历问题。

【示例】

假设我们有一个二维数组,需要遍历所有的元素,可以使用双重循环:

# 二维数组的遍历
for i in range(m):  # 第一层循环for j in range(n):  # 第二层循环print(matrix[i][j])  # 访问二维数组的元素

对于更高维度的数组,我们就可以使用三重循环、四重循环等:

# 三维数组的遍历
for i in range(m):  # 第一层循环for j in range(n):  # 第二层循环for k in range(p):  # 第三层循环print(matrix[i][j][k])  # 访问三维数组的元素

③应用场景

  • 多维数组/矩阵遍历:在处理多维数组、矩阵等数据结构时,需要使用嵌套循环。
  • 全排列/组合问题:例如,求解n个元素的所有排列或组合时,可以使用嵌套循环遍历每一种情况。
  • 暴力破解:当问题的解空间非常大,需要穷举所有可能的解时,常使用多重循环。

3 DFS与n重循环的区别与联系

类别DFS(深度优先搜索)n重循环
结构基于递归或栈的算法,遍历图或树的节点,适合路径和连通性问题用于多维数组、组合和暴力解法,主要处理遍历问题
回溯与非回溯通常涉及回溯:当一条路径探索失败时返回并尝试其他路径不涉及回溯,通常完全遍历每个组合或所有可能性
实现方式递归/栈结构,深度优先地探索树或图的节点嵌套循环结构,逐层遍历每种组合情况
应用场景图/树遍历、路径查找、连通性检测、组合问题等多维数组遍历、排列组合问题、穷举解空间等
相似性DFS可以看作是“带回溯的循环”,递归结构类似嵌套循环n重循环适用于处理解空间的所有可能性,也可以模拟DFS
多重DFS在组合问题中,可能需要多个DFS组合遍历类似多重循环多重循环用于遍历多个维度的数据或组合,适用于暴力破解

【示例对比】
假设我们需要寻找一个树中的所有路径:

①DFS方法(递归):

def dfs(node, path, all_paths):if node is None:returnpath.append(node.value)if not node.left and not node.right:  # 叶子节点all_paths.append(path.copy())else:dfs(node.left, path, all_paths)dfs(node.right, path, all_paths)path.pop()  # 回溯# 假设tree是二叉树
all_paths = []
dfs(tree.root, [], all_paths)
print(all_paths)

②n重循环方法(在解空间已知的情况下,可以模拟组合):

假设我们知道每一层的选择(如每一层有若干选择),可以用多重循环来遍历每一种可能的路径。

for i in range(m):  # 第一层for j in range(n):  # 第二层for k in range(p):  # 第三层# 访问某个路径print(i, j, k)

4 例题分析

在这里插入图片描述

题目地址:https://www.lanqiao.cn/problems/4124/learning/

【示例代码】

# ans表示方案数
ans = 0def dfs(depth, n, m):# depth:第几个小朋友# n:第一种糖果剩余量# m:第二种糖果剩余量# 当分完所有小朋友后保证手上没有糖果if depth == 7:if n == 0 and m == 0:global ansans += 1return# 枚举当前小朋友的糖果可能性# i 表示当前小朋友得到的第一种糖果的数量(0-5)for i in range(0, 6):# j 表示当前小朋友得到的第二种糖果的数量(0-5)for j in range(0, 6):if 2 <= i+j <=5 and i <= n and j <= m:# 调用dfs函数,进入下一层,处理下一个小朋友# 剩余的糖果数量不能为负dfs(depth + 1, n - i, m - j)# 初始化递归,depth从0开始(即从第一个小朋友开始分配)
dfs(0,9,16)
print(ans)

【执行流程】
本题使用 DFS(深度优先搜索) 来逐层递归地探索所有可能的糖果分配情况,并且通过 回溯 来保证每一种分配方案的合法性。

①函数调用栈的初始化
首先,调用 dfs(0, 9, 16),表示从第一个小朋友开始分配糖果,剩余的第一种糖果有 9 个,第二种糖果有 16 个。

②进入递归函数 dfs(depth, n, m)

第一个小朋友(depth = 0

  • n = 9(第一种糖果剩余 9 个)
  • m = 16(第二种糖果剩余 16 个)

depth = 0 时,程序会进入 for i in range(0, 6)for j in range(0, 6) 两个嵌套循环,分别枚举每个小朋友可以收到的糖果数量 i(第一种糖果数量)和 j(第二种糖果数量)。满足条件 2 <= i + j <= 5i <= nj <= m,程序继续递归。

该循环会探索每种可能的糖果分配方案,并递归到下一个小朋友。

递归到下一个小朋友(depth = 1
递归进入下一个小朋友的分配,并且更新剩余糖果数量 n - im - j。例如,如果当前小朋友分配了 2 个糖果(1 个第一种和 1 个第二种糖果),则递归调用 dfs(1, 9 - 1, 16 - 1),即剩余糖果为 n = 8m = 15

该过程会继续递归,直到 depth == 7

回溯的核心
递归调用 dfs(depth + 1, n - i, m - j) 时,n - im - j 表示剩余的糖果数量。递归过程中会试探不同的糖果分配方案,并在每个层级上回溯

④终止条件
当递归的 depth == 7 时,说明已经分配了所有 7 个小朋友的糖果。此时,程序会检查是否所有的糖果都已经分配完:if n == 0 and m == 0。如果是,说明这是一个合法的糖果分配方案,因此 ans += 1

⑤返回结果
当所有递归结束后,程序会输出 ans,即所有合法糖果分配方案的数量。

5067671

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DataX与DataX-Web安装与使用

DataX github地址&#xff1a;DataX/introduction.md at master alibaba/DataX GitHub 环境准备 Linux环境系统 JDK&#xff08;1.8及其以上版本&#xff0c;推荐1.8&#xff09; Python&#xff08;2或者3都可以&#xff09; Apache Maven 3.x&#xff08;源码编译安装…

语音助手关键模块整理

常见的 ASR 技术和平台包括&#xff1a; Google Speech-to-Text&#xff1a;这是一个非常流行的 ASR 服务&#xff0c;提供高精度的语音转文本功能&#xff0c;广泛应用于各种语音助手和智能设备。 Microsoft Azure Speech&#xff1a;微软的语音服务&#xff0c;也包括 ASR 技…

Day13 用Excel表体验梯度下降法

Day13 用Excel表体验梯度下降法 用所学公式创建Excel表 用Excel表体验梯度下降法 详见本Day文章顶部附带资源里的Excel表《梯度下降法》&#xff0c;可以对照表里的单元格公式进行理解&#xff0c;还可以多尝试几次不同的学习率 η \eta η来感受&#xff0c;只需要更改学习率…

NACA四位数字翼型

NACA四位数字翼型&#xff0c;以NACA 2412为例 第一位数字2 —相对弯度 第二位数字4 —相对弯度所有位置&#xff08;单位化后的&#xff09; 最末两位数字12 —相对厚度 所有NACA四位数字翼型的&#xff08;相对厚度所在的位置&#xff09;

解锁动态规划的奥秘:从零到精通的创新思维解析(3)

解锁动态规划的奥秘&#xff1a;从零到精通的创新思维解析&#xff08;3&#xff09; 前言&#xff1a; 小编在前几日书写了关于动态规划习题的博客&#xff08;PS&#xff1a;其实这些都是我的存稿&#xff0c;我已经好久没写博客了截止到现在&#xff0c;确实摆烂&#xff…

UE5仿漫威争锋灵蝶冲刺技能

这两天玩了一下漫威争锋Marvel Rivals&#xff0c;发现是UE5做的&#xff0c;对里面一些角色技能挺感兴趣的&#xff0c;想简单复刻一下技能功能&#xff0c;顺便复习一下学过的知识 首先把摄像机设置调整一下 CameraBoom里搜索lag 把摄像机延迟关掉 &#xff0c;这样摄像机就…

算法题(13):异或变换

审题&#xff1a; 这题的数据量比较大&#xff0c;所以暴力解法肯定是过不了了&#xff0c;我们根据异或运算的性质来找找规律&#xff0c;不难发现他是有循环周期的。 最终我们的周期是一个不小于n的2的最小整数次幂。 疑问一&#xff1a;为什么会有循环&#xff1f; 1.因为这…

oracle: create new database

用database configuration Assistant 引导创建数据库。记得给system,sys 设置自己的口令&#xff0c;便于添加新操作用户。 创建操作用户&#xff1a; -- 别加双引号&#xff0c;否则&#xff0c;无法用 create user geovindu identified by 888888; create user geovin identi…

IntelliJ IDEA 快捷键大全:提升开发效率的利器

目录 一、基础快捷键 1. 文件操作快捷键 2. 编辑&#xff08;Editing&#xff09; 2.1 代码补全与导航 2.2 代码编辑 2.3 代码折叠与展开 3. 查找与替换 4. 调试 5. 版本控制 高级快捷键 重构快捷键&#xff1a;让代码更加优雅 导航快捷键&#xff1a;快速定位代码 …

GOC编程 第2课 简单命令---直走和转弯命令

第2课 简单命令---直走和转弯命令 goc电子课程https://www.51goc.com/static/gocDemo/lesson.html?options%C5%81%C4%98%C5%96%C5%9F%C5%89%C5%89%C5%95%C5%94%C5%B3%C5%9E%C4%98%C4%80%C4%98%C5%94%C5%9F%C5%8D%C4%88%C4%98%C5%87&winNamelesson2 2A 闯关 goc电子课程htt…

MFC/C++学习系列之简单记录9——简单加法

MFC/C学习系列之简单记录9——简单加法 前言界面设计控件添加添加变量添加事件 后台代码总结 前言 基本的一些使用已经了解&#xff0c;那么就做个简单的加法来练手吧&#xff01; 界面设计 控件添加 在工具箱中选择Edit control和Static Text两个控件&#xff0c;分别设置为…

AOP 面向切面编程的实现原理

AOP是基于IOC的Bean加载来实现的&#xff0c;所以理解Spring AOP的初始化必须要先理解Spring IOC的初始化。然后就能找到初始化的流程和aop对应的handler&#xff0c;即parseCustomElement方法找到parse aop:aspectj-autoproxy的handler(org.springframework.aop.config.AopNam…

VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。—— 苏轼《水调歌头》 创作者&#xff1a;Code_流苏(CSDN) 目录 一、Java开发环境搭建二、VScode下载及安装三、VSCode配置Java环境四、运行测试五、背景图设置 很高兴你打开了这篇博客&#xff0c;更多详细的安装教程&…

【机器学习与数据挖掘实战】案例06:基于Apriori算法的餐饮企业菜品关联分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…

Go怎么做性能优化工具篇之基准测试

一、什么是基准测试&#xff08;Benchmark&#xff09; 在 Go 中&#xff0c;基准测试是通过创建以 Benchmark 开头的函数&#xff0c;并接收一个 *testing.B 类型的参数来实现的。testing.B 提供了控制基准测试执行的接口&#xff0c;比如设置测试执行的次数、记录每次执行的…

vulnhub靶场【WhowWantsToBeKing】之1

前言 靶机&#xff1a;whowantstobeking-1&#xff0c;ip地址192.168.1.67 攻击&#xff1a;kali &#xff0c;ip地址192.168.1.16 主机发现 使用arp-sacn -l或者netdiscover -r 192.168.1.1/24扫描 信息收集 使用nmap扫描端口 网站信息探测 访问80端口默认界面&#xff…

Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】

JAVA最新版JDK 23 安装教程详解 Java Development Kit (JDK) 23 是Oracle发布的最新长期支持版本 (LTS) 之一&#xff0c;它带来了许多新特性和改进。 本教程将详细介绍如何在Windows、macOS和Linux系统上安装JDK 23&#xff0c;并涵盖一些常见问题和解决方法。 一、 准备工作…

set的使用

文章目录 一、关联式容器二、set1、set的介绍2、set的使用2.1、元素的插入&#xff08;insert接口&#xff09;2.2、pair的简单讲解2.3、元素的查找&#xff08;find接口&#xff09;2.4、判断元素是否在set中&#xff08;count接口&#xff09;2.5、元素的删除&#xff08;era…

[Xshell] Xshell的下载安装使用、连接linux、 上传文件到linux系统-详解(附下载链接)

前言 xshell 链接&#xff1a;https://pan.quark.cn/s/57062561e81a 提取码&#xff1a;TK4K 链接失效&#xff08;可能被官方和谐&#xff09;可评论或私信我重发 安装 下载后解压得到文件 安装路径不要有中文 打开文件 注意&#xff01;360等软件会拦截创建注册表的行为&a…

基于蜂鸟视图的智慧可视化巡检管理系统研究

摘要 本文围绕蜂鸟视图研发的智慧可视化巡检管理系统展开研究&#xff0c;系统依托室内地图和室内定位技术&#xff0c;覆盖“规划、巡场、检查、上报”的完整业务流程。核心功能包括基于蓝牙定位的巡检点位置验证、可视化巡场地图的在线规划与导航、以及巡检路线轨迹的回放分析…