一文搞懂深度优先搜索(DFS)

2023-11-11

一、原理

深度优先搜索再得到一个新节点时立即对新节点进行遍历,从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4;如此反复以这种方式遍历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2,然后继续以上步骤。

从一个节点出发,使用DFS对一个图进行遍历时,能够遍历到的节点都是从初始节点可达的,DFS常用来解决这种 可达性 问题。

实现:递归栈(保存当前节点信息,当遍历新节点返回时能继续遍历当前节点)、标记(对已经遍历过的节点进行标记)。

二、应用

数组:

思路:对于没有被访问过且为‘1’的单元格,进行深度优先搜索,搜索过程中更新访问状态数组

class Solution {
    int[][] dir=new int[][]{{-1,0},{0,1},{1,0},{0,-1}};
    boolean[][] visited;
    int m,n;
    public int numIslands(char[][] grid) {
        m=grid.length;
        n=grid[0].length;
        visited=new boolean[m][n];
        for(int i=0;i<m;i++){
            Arrays.fill(visited[i],false);
        }
        int res=0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(!visited[i][j]&&grid[i][j]=='1'){
                    res++;
                    dfs(grid,i,j);
                }
            }
        }
        return res;
    }
    public void dfs(char[][] grid,int x,int y){
        visited[x][y]=true;
        for(int[] arr:dir){
            int newX=x+arr[0];
            int newY=y+arr[1];
            if(newX<0||newX>=m||newY<0||newY>=n||visited[newX][newY]||grid[newX][newY]=='0'){
                continue;
            }
            dfs(grid,newX,newY);
        }
    }
}

树:

思路: dfs过程中改变targetSum的值,直到叶子节点且targetSum为0时找到一条路径。

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>>res=new LinkedList<List<Integer>>();
        Deque<Integer>path=new LinkedList<Integer>();
        dfs(root,targetSum,path,res);
        return res;
    }
    public void dfs(TreeNode root,int targetSum,Deque<Integer>path,List<List<Integer>>res){
        if(root==null){
            return;
        }
        path.offerLast(root.val);
        targetSum-=root.val;
        if(targetSum==0&&(root.left==null&&root.right==null)){
            res.add(new LinkedList<Integer>(path));
        }
        dfs(root.left,targetSum,path,res);
        dfs(root.right,targetSum,path,res);
        path.pollLast();
    }
}

思路:第一次深度优先从root开始搜索每个节点的父节点并保存在哈希表中,因为每个节点的值不充分,可以用节点的值作为key,第二次深度搜索从目标节点开始,对节点的左子树、右子树、根分别进行搜索,找到与目标节点距离为K的节点记录到结果。

class Solution {
    Map<Integer,TreeNode>parents=new HashMap<>();
    List<Integer>res=new ArrayList<>();
    public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        findParents(root);
        findans(target,null,k,0);
        return res;
    }
    public void findParents(TreeNode root){
        if(root==null) return;
        if(root.left!=null){
            parents.put(root.left.val,root);
            findParents(root.left);
        }
        if(root.right!=null){
            parents.put(root.right.val,root);
            findParents(root.right);
        }
    }
    public void findans(TreeNode node,TreeNode from,int k,int depth){
        if(node==null){
            return;
        }
        if(depth==k){
            res.add(node.val);
            return;
        }
        if(node.left!=from){
            findans(node.left,node,k,depth+1);
        }
        if(node.right!=from){
            findans(node.right,node,k,depth+1);
        }
        if(parents.get(node.val)!=from){
            findans(parents.get(node.val),node,k,depth+1);
        }
    }
}

图:

思路:邻接表构图,DFS搜索过程中判断是否有环

class Solution {
    List<List<Integer>>graph;
    int[] visited;
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        graph=new ArrayList<>();
        visited=new int[numCourses];
        Arrays.fill(visited,0);
        for(int i=0;i<numCourses;i++){
            graph.add(new ArrayList<>());
        }
        int n=prerequisites.length;
        for(int i=0;i<n;i++){
            graph.get(prerequisites[i][0]).add(prerequisites[i][1]);
        }
        for(int i=0;i<numCourses;i++){
            if(!dfs(i)){
                return false;
            }
        }
        return true;
    }
    public boolean dfs(int i){
        if(visited[i]==1) return false;
        if(visited[i]==-1) return true;
        visited[i]=1;
        for(int j:graph.get(i)){
            if(!dfs(j)){
                return false;
            }
        }
        visited[i]=-1;
        return true;
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文搞懂深度优先搜索(DFS) 的相关文章

  • Mysql 数据库

    数据库基础 1 什么是数据库 用来存储数据 数据库可在硬盘及内存中存储数据 数据库与文件存储数据的区别 数据库本质也是通过文件来存储数据 数据库的概念就是系统的管理存储数据的文件 数据库介绍 本质就是存储数据的C S架构的socket套接字
  • Day.1 LeetCode刷题练习(最长公共前缀 C/C++两种解法)

    题目 例子 分析题目 主要目的 求出各个字符串的公共前缀 思路 本人解法 用所给实例来看 不难看出我们可以直接以竖着对应来查看是否是公共前缀 这样就有了一定的思路 然后接着想如何让他找到最长的公共前缀后就 停止下来呢 这样就能想到 从最短的
  • BP神经网络与Python实现

    人工神经网络是一种经典的机器学习模型 随着深度学习的发展神经网络模型日益完善 联想大家熟悉的回归问题 神经网络模型实际上是根据训练样本创造出一个多维输入多维输出的函数 并使用该函数进行预测 网络的训练过程即为调节该函数参数提高预测精度的过程
  • 直线检测方法—LSD论文翻译

    附原文链接 LSD a Line Segment Detector 摘 要 LSD是一个线段检测器 能够在线性时间内得到亚像素级精度的检测结果 它无需调试参数就可以适用于任何数字图像上 并且能够自我控制错误数量的检测 平均来说 一个图像中允
  • LeetCode第79题:单词搜索

    给定一个 m x n 二维字符网格 board 和一个字符串单词 word 如果 word 存在于网格中 返回 true 否则 返回 false 单词必须按照字母顺序 通过相邻的单元格内的字母构成 其中 相邻 单元格是那些水平相邻或垂直相邻
  • DDP入门

    DDP 即动态动态规划 可以用于解决一类带修改的DP问题 我们从一个比较简单的东西入手 最大子段和 带修改的最大子段和其实是常规问题了 经典的解决方法是用线段树维护从左 右开始的最大子段和和区间最大子段和 然后进行合并 现在我们换一种方法来
  • 数据结构与算法学习总结(六)——字符串的模式匹配算法

    基本概念 字符串是一种特殊的线性表 即元素都是 字符 的线性表 字符是组成字符串的基本单位 字符的取值依赖于字符集 例如二进制的字符集为0 1 则取值只能为 0 1 再比如英语语言 则包括26个字母外加标点符号 例如 abcde 就是一个字
  • Hash映射理解

    先说数组 数组优点之一 能通过索引很快定位到值 hashmap 就是利用了数组这个优点 对比 线性映射 定义一个数组 数组的元素是结构体 结构体包括 一对键 值 伪代码表示 a 0 struct Bill 5 a 1 struct KK 6
  • 亚利桑那州立大学周纵苇:研习 U-Net ——现有的分割网络创新

    雷锋网AI研习社按 经典的 Encoder Decoder 结构在目标分割问题中展现出了举足轻重的作用 然而这样一个相对固定的框架使得模型在感受野大小和边界分割精度两方面很难达到兼顾 本次公开课 讲者以 U Net 为案例分析 总结现有的分
  • 数据结构小白之插入排序算法

    1 插入排序 1 1 思路 将n个需要排序的元素看成两个部分 一个是有序部分 一个是无序部分 开始的时候有序表只有一个元素 无序表有n 1个元素 排序过程中每次从无序表中取出元素 然后插入到有序表的适当位置 从而成为新的有序表 类似排队 如
  • 字符串09--表示数值的字符串

    字符串09 表示数值的字符串 jz53 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 请实现一个函数用来判断字符串是否表示数值 包括整数和小数 例如 字符串 100 5e2 123 3 1416 和 1E 16 都表示数值
  • 用指针访问一维数组

    文章目录 顺序查找 数组方式实现 指针实现方式 对一位数组元素的访问有三种方式 指针变量的关系运算 引例 数组实现方式 主函数 指针实现方式 主函数 一维数组作为函数的参数 实际应用 顺序查找 要求用指针实现 在整数集合r中顺序查找与给定值
  • 数理统计知识整理——回归分析与方差分析

    题记 时值我的北科研究生第一年下 选学 统计优化 课程 备考促学 成此笔记 以谨记 1 线性回归 1 1 原理分析 要研究最大积雪深度x与灌溉面积y之间的关系 测试得到近10年的数据如下表 使用线性回归的方法可以估计x与y之间的线性关系 线
  • 插入排序超详解释,一看就懂

    目录 一 插入排序的相关概念 1 基本思想 2 基本操作 有序插入 二 插入排序的种类 三 直接插入排序 1 直接插入排序的过程 顺序查找法查找插入位置 2 使用 哨兵 直接插入排序 四 直接插入排序算法描述 五 折半插入排序 1 查找插入
  • 索引优化之Explain 及慢查询日志

    索引 本质是数据结构 简单理解为 排好序的快速查找数据结构 以索引文件的形式存储在磁盘中 目的 提高数据查询的效率 优化查询性能 就像书的目录一样 优势 提高检索效率 降低IO成本 排好序的表 降低CPU的消耗劣势 索引实际也是一张表 该表
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • 【数据结构】双链表的定义和操作

    目录 1 双链表的定义 2 双链表的创建和初始化 3 双链表的插入节点操作 4 双链表的删除节点操作 5 双链表的查找节点操作 6 双链表的更新节点操作 7 完整代码 嗨 我是 Filotimo 很高兴与大家相识 希望我的博客能对你有所帮助
  • 1796. 字符串中第二大的数字

    1796 字符串中第二大的数字 java class Solution public int secondHighest String s int max 1 for char ch s toCharArray if Character i
  • C++ AVL树(四种旋转,插入)

    C AVL树 四种旋转 插入 一 AVL树的概念及性质 二 我们要实现的大致框架 1 AVL树的节点定义 2 AVL树的大致框架 三 插入 1 插入逻辑跟BST相同的那一部分 2 修改平衡因子
  • 按照层次遍历结果打印完全二叉树

    按照层次遍历结果打印完全二叉树 按照推论结果 l 层首个节点位置 2 h l 1 l 层节点间距 2 h l 1 1 编码实现 public static

随机推荐

  • tq210-uboot eth dm9000移植

    这个芯片与ok210一样 因此将代码搬过来就ok了 但是使用tftp 启动 TQ210自带的kernel依旧是 Start kerneling 就啥都没有了 启动设置如下 set machid 998 set serverip 192 16
  • MIPI CSI协议

    PCLK 像素时钟 每个时钟对应了一个像素数据 HSYNC 行同步信号 VSYNC 帧同步信号 像素字节转换层 sensor输出的4种数据类型 YUV422 RGB RAW JPEG RGB Data type description 0x
  • 《面试准备》c/c++最少装箱问题(动态规划)

    问题描述 出口质量不等的钻石n颗 至少需要多少个箱子 输入 一个整数m 箱子最大承载重量 一个整数n 钻石的个数 第i颗钻石的质量大小a i 输出 最少需要多少箱子 举例 输入 10 5 4 5 7 3 6 输出 3 c 代码实现 动态规划
  • java8 HashMap

    java8 HashMap 8以前HashMap是用位桶 链表的形式 8以后HashMap是用位桶 链表 红黑树的形式 冲突节点数大于8时 转换成红黑树
  • Spark 架构,计算

    1 架构设计图 2 用户交互方式 1 spark shell spark命令行方式来操作spark作业 多用于简单的学习 测试 简易作业操作 2 spark submit 通过程序脚本 提交相关的代码 依赖等来操作spark作业 最多见的提
  • requests 登陆的几种方法

    一 通过账户名和密码登陆访问 formData username password 需要带 cookies 则带上 cookies res req post url data formData cookies cookies headers
  • sqlite,mysql,access对比

    SQLite是一个小型的桌面型数据库 轻量级的 绿色 开源 轻便 SQLite其实只是一个文件 以及内部格式方案而已 下面做几个简单的对比 SQLite VS 文本文件或二进制文件 他们的本质是相同的 都是一个文件 但是SQLite定义了更
  • Matlab:大小写和空格敏感性

    Matlab 大小写和空格敏感性 Matlab是一种强大的计算机语言 是许多科学家 工程师和其他专业人士使用的首选语言之一 当你开始学习Matlab时 可能会发现它与其他编程语言有些不同 其中一个最显著的区别就是Matlab对大小写和空格的
  • VScode无法启动问题解决思路

    VScode无法启动问题解决 过程 后记 过程 在不知道为什么的情况下 VScode启动没有反应 然后尝试解决问题 进行以下尝试 重启 重装 卸载注册表重装 删除配置重装 均不行 然后本来想打算重装系统了 最后还是接着搞一搞 然后就打算用P
  • MySQL字符集设置

    ERROR 1366 HY000 Incorrect string value错误解决办法 通过命令查看Mysql默认字符集的相关设置 mysql gt SHOW VARIABLES LIKE character Variable name
  • 9.Java面向对象基础(上)

    个人简介 作者简介 大家好 我是W chuanqi 一个编程爱好者 个人主页 W chaunqi 支持我 点赞 收藏 留言 愿你我共勉 没有什么比勇气更温文尔雅 没有什么比怯懦更冷酷无情 文章目录 面向对象 上 1 面向对象的思想 1 1
  • 前端开发工程师

    岗位职责 1 负责网站前端页面的开发工作 2 根据产品需求 分析并给出最优的页面前端结构解决方案 3 与设计师合作完成网站页面前端的特效和最新的应用 4 与产品经理合作完成前端网站交互效果的实现 职位要求 1 掌握各种修图软件 如PS Fi
  • 数据库系统工程师真题及详解(2015~2021)

    2015 2021年软考中级数据库系统工程师真题及答案详解 链接 https pan baidu com s 1VMXyrl1cBX Gwoz0EU Dow pwd nt0a 提取码 nt0a 据了解 考试试题大部分与历年真题相近 祝大家软
  • 计组

    目录 一 知识点 1 寻址方式什么 2 根据操作数所在的位置 都有哪些寻址方式 3 直接寻址 4 立即寻址 5 隐含寻址 6 相对寻址 7 寄存器 8 寄存器 寄存器型 RR 寄存器 存储器型 RS 和存储器 存储器型 SS 9 基址寻址方
  • 类成员函数的重载、覆盖和隐藏区别

    转自 http blog csdn net yanjun 1982 archive 2005 09 02 470405 aspx 这三个概念都是与OO中的多态有关系的 如果单是区别重载与覆盖这两个概念是比较容易的 但是隐藏这一概念却使问题变
  • 理清概念:同步与异步

    广义的同步与异步 在广义上 同步和异步是描述两个或多个事件 操作或进程之间的关系 同步意味着事件 操作或进程是有序的 一个操作必须在另一个操作完成后开始执行 异步则意味着事件 操作或进程是独立的 可以在不等待其他操作完成的情况下开始执行 同
  • CentOS7 RPM包管理功能总结及示例

    RPM是红帽软件包管理器 主要用来对RPM包进行安装 升级 卸载 查询 校验和数据库维护的管理操作 安装 语法 rpm i install install options PACKAGE FILE i 安装一个新包 PACKAGE FILE
  • 关于C#中get和set

    转自 http blog sina com cn s blog 82526aa60100txtx html 在程序中经常碰到get set 不甚明白 在网上查询时也说的迷迷糊糊 所以整理下 以学的明白透彻点 有两个类person publi
  • stm32串口驱动和esp8266的使用

    写在前面 本文并不对相关知识进行讲解 只是这次的实验课要实现的任务有些复杂 我也踩了一些坑 对代码实现思路进行复现和记录 并不是技术科普性文章 基础知识还是要自己有所掌握 1 stm32的串口通讯 开发板 stm32f407zgt6课程学习
  • 一文搞懂深度优先搜索(DFS)

    一 原理 深度优先搜索再得到一个新节点时立即对新节点进行遍历 从节点 0 出发开始遍历 得到到新节点 6 时 立马对新节点 6 进行遍历 得到新节点 4 如此反复以这种方式遍历新节点 直到没有新节点了 此时返回 返回到根节点 0 的情况是