在计算机科学领域,搜索算法是解决问题的重要工具,其中深度优先搜索(Depth-First Search,简称 DFS)凭借其简洁高效的特性,在图论、回溯、拓扑排序等众多场景中发挥着关键作用。无论是 LeetCode 算法题,还是考研计算机专业基础综合(408)考试,深度优先搜索都是高频考点。

深度优先搜索算法核心思路

深度优先搜索的基本思想是沿着一条路径尽可能深地探索,直到无法继续或达到目标状态,然后回溯到上一个节点,继续探索其他路径,直至遍历完所有可达节点。在图结构或树结构中,DFS 可以用来遍历所有节点、寻找路径、检测连通性等。

1.1 算法实现方式

DFS 通常有两种实现方式:递归和迭代(借助栈数据结构)。

  • 递归实现:利用函数调用栈,从起始节点开始,不断递归访问相邻节点,当达到边界条件(如访问过的节点、无相邻节点)时回溯。代码简洁直观,但可能因递归深度过深导致栈溢出。
  • 迭代实现:手动维护一个栈,将起始节点入栈,每次取出栈顶节点,访问其未访问过的相邻节点并将其入栈,直到栈为空。这种方式可避免栈溢出问题,适用于大规模数据。

1.2 算法流程

以图结构为例,DFS 的基本流程如下:

  1. 选择一个起始节点,标记为已访问。
  1. 从起始节点出发,找到一个未访问的相邻节点,将其标记为已访问,并以该节点为新的起始节点,递归执行步骤 2。
  1. 当当前节点的所有相邻节点都已访问时,回溯到上一个节点,继续执行步骤 2。
  1. 重复步骤 2 和 3,直到所有可达节点都被访问。

绘制出的 DFS 递归实现的流程图:

为了更直观地理解,假设我们有如下无向图:

从节点 A 开始进行 DFS,访问顺序可能为 A -> B -> D -> E -> C(顺序不唯一,取决于具体实现)。

LeetCode 例题实战

例题 1:200. 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和 / 或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid = [

["1","1","1","1","0"],

["1","1","0","1","0"],

["1","1","0","0","0"],

["0","0","0","0","0"]

]

输出:1

解题思路:使用 DFS 遍历二维网格,当遇到'1'时,将其及其相邻的'1'全部标记为已访问(可以将'1'改为'0'),每完成一次 DFS,岛屿数量加 1。


public class NumIslands {public int numIslands(char[][] grid) {if (grid == null || grid.length == 0) {return 0;}int m = grid.length;int n = grid[0].length;int count = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == '1') {dfs(grid, i, j);count++;}}}return count;}private void dfs(char[][] grid, int i, int j) {int m = grid.length;int n = grid[0].length;if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == '0') {return;}grid[i][j] = '0';dfs(grid, i - 1, j);dfs(grid, i + 1, j);dfs(grid, i, j - 1);dfs(grid, i, j + 1);}}

例题 2:79. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中 “相邻” 单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"

输出:true

解题思路:从网格中的每个单元格开始进行 DFS,当当前字符与单词当前字符匹配时,继续向相邻单元格递归搜索。为避免重复访问,使用一个布尔数组记录单元格是否已被访问。如果找到匹配的路径,返回true;遍历完所有单元格仍未找到,则返回false。

public class WordSearch {public boolean exist(char[][] board, String word) {int m = board.length;int n = board[0].length;boolean[][] visited = new boolean[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (dfs(board, word, 0, i, j, visited)) {return true;}}}return false;}private boolean dfs(char[][] board, String word, int index, int i, int j, boolean[][] visited) {int m = board.length;int n = board[0].length;if (index == word.length()) {return true;}if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || board[i][j] != word.charAt(index)) {return false;}visited[i][j] = true;boolean result = dfs(board, word, index + 1, i - 1, j, visited) ||dfs(board, word, index + 1, i + 1, j, visited) ||dfs(board, word, index + 1, i, j - 1, visited) ||dfs(board, word, index + 1, i, j + 1, visited);visited[i][j] = false;return result;}}

考研 408 例题分析

例题:已知一个无向连通图的邻接表存储结构,编写算法判断图中是否存在回路。

解题思路:利用 DFS 遍历图,在遍历过程中记录每个节点的前驱节点。当访问到一个已访问过的节点,且该节点不是当前节点的前驱节点时,说明存在回路。

import java.util.ArrayList;import java.util.List;class Graph {int V;List<List<Integer>> adj;Graph(int v) {V = v;adj = new ArrayList<>(v);for (int i = 0; i < v; i++) {adj.add(new ArrayList<>());}}void addEdge(int v, int w) {adj.get(v).add(w);adj.get(w).add(v);}boolean isCyclic() {boolean[] visited = new boolean[V];for (int i = 0; i < V; i++) {if (!visited[i]) {if (dfs(i, -1, visited)) {return true;}}}return false;}private boolean dfs(int v, int parent, boolean[] visited) {visited[v] = true;for (int i : adj.get(v)) {if (!visited[i]) {if (dfs(i, v, visited)) {return true;}} else if (i != parent) {return true;}}return false;}}public class CyclicGraph {public static void main(String[] args) {Graph g1 = new Graph(5);g1.addEdge(1, 0);g1.addEdge(0, 2);g1.addEdge(2, 1);g1.addEdge(0, 3);g1.addEdge(3, 4);if (g1.isCyclic()) {System.out.println("Graph contains cycle");} else {System.out.println("Graph does not contain cycle");}Graph g2 = new Graph(3);g2.addEdge(0, 1);g2.addEdge(1, 2);if (g2.isCyclic()) {System.out.println("Graph contains cycle");} else {System.out.println("Graph does not contain cycle");}}}

总结

深度优先搜索算法以其独特的搜索策略,在解决各类问题中展现出强大的能力。通过 LeetCode 例题和考研 408 真题的实战演练,我们不仅掌握了 DFS 在不同场景下的应用,还熟悉了其 Java 代码实现。在实际编程和考研备考中,熟练运用 DFS 算法,能够有效提升问题解决能力。后续可以进一步研究 DFS 与其他算法的结合应用,探索其在更复杂场景下的优化与拓展。

希望本文能够帮助读者更深入地理解深度优先搜索算法,并在实际项目中发挥其优势。谢谢阅读!


希望这份博客能够帮助到你。如果有其他需要修改或添加的地方,请随时告诉我。

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

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

相关文章

vue create 和npm init 创建项目对比

以下是关于 vue create 和 npm init 的对比分析&#xff1a; 1. 定位与功能 vue create 定位&#xff1a;Vue 官方提供的脚手架工具&#xff0c;基于 Vue CLI&#xff0c;用于快速创建标准化的 Vue 项目&#xff0c;支持 Vue 2 和 Vue 3。功能&#xff1a;提供交互式配置&…

C++ bitset 模板类

bitset<256> 数据类型详解 bitset<256> 是 C 标准库中的一个模板类&#xff0c;用于处理固定大小的位集合&#xff08;Bit Set&#xff09;。它可以高效地操作和存储二进制位&#xff0c;特别适合需要处理大量布尔标志或简单计数的场景。 基本定义与特性 1. 模板参…

通信握手言和:PROFINET转EtherCAT网关让汽轮机振动数据“破壁”传输

某大型电厂的关键汽轮机设备采用EtherCAT振动传感器进行实时监测&#xff0c;但由于工厂PLC振动分析系统基于PROFINET协议&#xff0c;数据无法直接接入&#xff0c;导致振动数据延迟、预警滞后&#xff0c;严重影响设备健康管理。传统的人工巡检和定期维护难以捕捉早期机械故障…

golang 中当 JSON 数据缺少结构体(struct)中定义的某些字段,会有异常吗

目录关键影响示例演示潜在问题与解决方案问题 1&#xff1a;逻辑错误&#xff08;零值干扰&#xff09;问题 2&#xff1a;忽略可选字段问题 3&#xff1a;第三方库验证最佳实践总结在 Go 语言中&#xff0c;当 JSON 数据缺少结构体&#xff08;struct&#xff09;中定义的某些…

Fiddler 中文版怎么配合 Postman 与 Wireshark 做多环境接口调试?

现代项目中&#xff0c;开发、测试、预发布、生产环境往往分离配置&#xff0c;前端在开发过程中需要频繁切换接口域名、验证多环境表现。而接口升级或项目迭代时&#xff0c;还需要做回归测试&#xff0c;确保老版本接口仍能兼容&#xff0c;避免线上事故。这些环节若仅靠代码…

钉钉小程序开发技巧:getSystemInfo 系统信息获取全解析

在钉钉小程序开发中&#xff0c;获取设备系统信息是实现跨平台适配和优化用户体验的关键环节。本文将深入解析 dd.getSystemInfo 接口的使用方法、技术细节与实际应用场景&#xff0c;帮助开发者高效应对多终端开发挑战。一、接口功能与核心价值dd.getSystemInfo 是钉钉小程序提…

Java项目Maven配置JDK1.8全攻略

目录 &#x1f9e9; 一、全局环境变量配置&#xff08;推荐系统级统一&#xff09; ⚙️ 二、Maven全局配置&#xff08;多项目统一&#xff09; &#x1f4c2; 三、项目级配置&#xff08;推荐团队协作&#xff09; &#x1f4bb; 四、IDE配置&#xff08;辅助验证&#x…

使用tensorflow的线性回归的例子(六)

波士顿房价 import matplotlib.pyplot as plt %matplotlib inline import tensorflow as tf import numpy as np from sklearn.datasets import load_boston import sklearn.linear_model as sk boston load_boston() features np.array(boston.data) labels np.arra…

YOLOv11深度解析:Ultralytics新一代目标检测架构创新与实战指南

🔍 2024年Ultralytics重磅推出YOLOv11**:在精度与速度的平衡木上再进一步,参数减少22%,推理速度提升2%,多任务支持全面升级! 🚀 一、YOLOv11核心创新:轻量化与注意力机制的完美融合 YOLOv11并非颠覆性重构,而是通过模块级优化实现“少参数、高精度、快推理”的目标…

基于 SpringBoot+Vue.js+ElementUI 的 “花开富贵“ 花园管理系统设计与实现7000字论文

摘要 本论文详细阐述了基于 SpringBoot、Vue.js 和 ElementUI 的 "花开富贵" 花园管理系统的设计与实现过程。该系统旨在为花园管理者提供高效、便捷的花园信息管理平台&#xff0c;实现花卉信息、员工、客户、订单等全方位管理功能。论文首先分析了花园管理系统的研…

RESTful API 安装使用教程

一、RESTful API 简介 REST&#xff08;Representational State Transfer&#xff09;是一种基于 Web 的架构风格&#xff0c;RESTful API 是使用 HTTP 协议并遵循 REST 原则设计的 API 接口。其核心思想是&#xff1a;使用标准 HTTP 方法&#xff08;GET、POST、PUT、DELETE&…

【行云流水ai笔记】粗粒度控制:推荐CTRL、GeDi 细粒度/多属性控制:推荐TOLE、GPT-4RL

TOLE模型完整启动方法指南 TOLE (Token-level Optimization with Language Models) 是一种基于强化学习的可控文本生成方法&#xff0c;通过token级别的反馈实现对文本多个属性的精确控制。以下是完整的启动方法指南&#xff1a; 1. 环境准备 1.1 创建虚拟环境 conda creat…

【沉浸式解决问题】idea开发中mapper类中突然找不到对应实体类

目录 一、问题描述二、场景还原三、原因分析四、解决方案 一、问题描述 mapper类继承了mybatis-plus的BaseMapper&#xff0c;泛型需要填入实体类&#xff0c;但是不知怎么地突然实体类就报错了&#xff0c;显示没有这个类 二、场景还原 实体类就是死活报错找不到&#xff0c;所…

初学python的我开始Leetcode题11-2

提示&#xff1a;100道LeetCode热题-11-1主要是二分查找相关&#xff0c;包括三题&#xff1a;搜索旋转排序数组、寻找旋转排序数组中的最小值、寻找两个正序数组的中位数。由于初学&#xff0c;所以我的代码部分仅供参考。前言上次的三道二分查找题较为基础&#xff0c;主要是…

Python 数据分析与可视化 Day 12 - 建模前准备与数据集拆分

✅ 今日目标 掌握建模前常见准备步骤学会使用 train_test_split() 将数据划分为训练集和测试集理解特征&#xff08;X&#xff09;与标签&#xff08;y&#xff09;的区分学习常见建模流程的输入要求&#xff08;格式、维度&#xff09;&#x1f4d8; 一、建模前准备流程概览 数…

Swagger 安装使用教程

一、Swagger 简介 Swagger 是一套开放源代码的 API 文档生成工具链&#xff0c;现归属于 OpenAPI 规范。它支持 RESTful API 的定义、生成、测试和文档自动化。常见的使用工具包括 Swagger UI、Swagger Editor、Swagger Codegen 以及 SpringFox&#xff08;Spring 集成库&…

【seismic unix相速度分析-频散曲线】

介绍Seismic Unix Seismic Unix&#xff08;SU&#xff09;是一个开源的地震数据处理软件包&#xff0c;主要用于地震数据的处理、分析和可视化。它由科罗拉多矿业学院的Center for Wave Phenomena开发&#xff0c;广泛应用于学术研究和工业领域。SU提供了一系列命令行工具&am…

3.前端和后端参数不一致,后端接不到数据的解决方案

目录 1.问题背景: (1).前端代码: (2).后端代码: (3).问题分析: [1]前端参数构造错误: [2].Api请求配置错误: 2.解决方案 (1).修改 role.js 中的 API 方法 (2).前端组件中的调用方式改成下面的而不是继续拼接了 3.总结: 1.问题背景: 我在接口开发过程中&#xff0c;前…

SpringBoot:整合quartz实现定时任务-MisFire的处理

文章目录 一、什么是MisFire二、MisFire发生的情况三、MisFire的补偿策略四、代码实现 一、什么是MisFire 简单理解为&#xff1a;定时任务&#xff0c;所错过的触发 二、MisFire发生的情况 1、资源紧张&#xff0c;定时任务请求不到对应的线程。 2、调度器关闭。 3、设置定…

返回json,优雅处理转换(如 0.85 → “85.00%“)

核心解决方案 通过 自定义序列化器 JsonSerialize 注解&#xff0c;实现 BigDecimal 到百分比字符串的自动转换。 1.1 自定义序列化器代码 java import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterx…