BFS 类似,深度优先搜索(DFS)是用于在树/图中遍历/搜索的另一种重要算法。也可以在更抽象的场景中使用。

正如树的遍历中所提到的,我们可以用 DFS 进行 前序遍历中序遍历后序遍历。在这三个遍历顺序中有一个共同的特性:除非我们到达最深的结点,否则我们永远不会回溯

这也是 DFSBFS 之间最大的区别,BFS永远不会深入探索,除非它已经在当前层级访问了所有结点

模版

递归模版

有两种实现 DFS 的方法。第一种方法是进行递归:

boolean DFS(Node cur, Node target, Set<Node> visited) {return true if cur is target;for (next : each neighbor of cur) {if (next is not in visited) {add next to visted;return true if DFS(next, target, visited) == true;}}return false;
}

当我们递归地实现 DFS 时,似乎不需要使用任何栈。但实际上,我们使用的是由系统提供的隐式栈,也称为调用栈(Call Stack)。

显式栈模板

递归解决方案的优点是它更容易实现。 但是,存在一个很大的缺点:如果递归的深度太高,你将遭受堆栈溢出。 在这种情况下,您可能会希望使用 BFS,或使用 显式栈 实现 DFS

boolean DFS(int root, int target) {Set<Node> visited;Stack<Node> s;add root to s;while (s is not empty) {Node cur = the top element in s;return true if cur is target;for (Node next : the neighbors of cur) {if (next is not in visited) {add next to s;add next to visited;}}remove cur from s;}return false;
}

例题

1.岛屿数量

  • 难度:Medium

题目描述

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000
输出: 1

示例 2:

输入:
11000
11000
00100
00011
输出: 3

解题思路及实现

笔者曾经在 这篇文章 中展示了如何使用 BFS 解决这道题,事实上该题使用 DFS 更简单,因为前者还需要一个队列维护 广度优先搜索 过程中搜索的层级信息。

使用 DFS 解题如下:

public class B200NumIslands {public int numIslands(char[][] grid) {int nr = grid.length;if (nr == 0) return 0;int nc = grid[0].length;if (nc == 0) return 0;int result = 0;for (int r = 0; r < nr; r++) {for (int c = 0; c < nc; c++) {if (grid[r][c] == '1') {result++;dfs(grid, r, c);}}}return result;}private void dfs(char[][] grid, int r, int c) {int nr = grid.length;int nc = grid[0].length;// 排除边界外的情况if (r >= nr || c >= nc || r < 0 || c < 0) return;// 排除边界外指定位置为 '0' 的情况if (grid[r][c] == '0') return;// 该位置为一个岛,标记为已探索grid[r][c] = '0';dfs(grid, r - 1, c);  // topdfs(grid, r + 1, c);  // bottomdfs(grid, r, c - 1);  // leftdfs(grid, r, c + 1);  // right}
}

2.克隆图

  • 难度:Medium

题目描述

给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)

图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。

class Node {public int val;public List<Node> neighbors;
}

更详细的题目描述参考 这里 :
https://leetcode-cn.com/problems/clone-graph/

解题思路及实现

题目比较难理解,需要注意的是:

  1. 因为是 深拷贝 ,因此所有节点都需要通过 new 进行实例化,即需要遍历图中的每个节点,因此解决方案就浮现而出了,使用 DFS 或者 BFS 即可;
  2. 对每个已经复制过的节点进行标记,避免无限循环导致堆栈的溢出。

DFS 实现代码如下:

class Solution {public Node cloneGraph(Node node) {HashMap<Node,Node> map = new HashMap<>();return dfs(node, map);}private Node dfs(Node root, HashMap<Node,Node> map) {if (root == null) return null;if (map.containsKey(root)) return map.get(root);Node clone = new Node(root.val, new ArrayList());map.put(root, clone);for (Node nei: root.neighbors) {clone.neighbors.add(dfs(nei, map));}return clone;}
}

3.目标和

  • 难度:Medium

题目描述

给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 +- 中选择一个符号添加在前面。

返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

示例 1:

输入: nums: [1, 1, 1, 1, 1], S: 3
输出: 5
解释:>-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3一共有5种方法让最终目标和为3。

注意:

1.数组非空,且长度不会超过20。
2.初始的数组的和不会超过1000。
3.保证返回的最终结果能被32位整数存下。

解题思路及实现

说实话这道题真没想到使用 DFS 暴力解决,还是经验太少了,这道题暴力解法是完全可以的,而且不会超时,因为题目中说了数组长度不会超过20,20个数字的序列,组合方式撑死了也就 2^20 种组合:

public class Solution {int count = 0;public int findTargetSumWays(int[] nums, int S) {dfs(nums, 0, 0, S);return count;}private void dfs(int[] nums, int index, int sum, int S) {if (index == nums.length) {if (sum == S) count++;} else {dfs(nums, index + 1, sum + nums[index], S);dfs(nums, index + 1, sum - nums[index], S);}}
}

4.二叉树的中序遍历

  • 难度:Medium

题目描述

给定一个二叉树,返回它的中序遍历。

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

解题思路及实现

二叉树相关真的是非常有趣的一个算法知识点(因为这道题非常具有代表性,我觉得面试考到的概率最高2333…),后续笔者会针对该知识点进行更详细的探究,本文列出两个解决方案。

1.递归法

public class Solution {// 1.递归法public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();dfs(root, list);return list;}private void dfs(TreeNode node, List<Integer> list) {if (node == null) return;// 中序遍历:左中右if (node.left != null)dfs(node.left, list);list.add(node.val);if (node.right != null)dfs(node.right, list);}
}

2.使用栈

public class Solution {// 2.使用栈public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();TreeNode curr = root;while (!stack.isEmpty() || curr != null) {while (curr != null) {stack.push(curr);curr = curr.left;}curr = stack.pop();list.add(curr.val);curr = curr.right;}return list;}
}

参考 & 感谢

文章绝大部分内容节选自LeetCode栈和深度优先搜索 概述:

  • https://leetcode-cn.com/explore/learn/card/queue-stack/219/stack-and-dfs/

例题:

  • https://leetcode-cn.com/problems/number-of-islands
  • https://leetcode-cn.com/problems/clone-graph/
  • https://leetcode-cn.com/problems/target-sum/
  • https://leetcode-cn.com/problems/binary-tree-inorder-traversal/

关于我

Hello,我是 却把清梅嗅 ,如果您觉得文章对您有价值,欢迎 ❤️,也欢迎关注我的 博客 或者 GitHub。

如果您觉得文章还差了那么点东西,也请通过关注督促我写出更好的文章——万一哪天我进步了呢?

  • 我的Android学习体系
  • 关于文章纠错
  • 关于知识付费
  • 关于《反思》系列

栈和深度优先搜索(DFS)相关推荐

  1. 一文搞定深度优先搜索(DFS)与广度优先搜索(BFS)【含完整源码】

    写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...

  2. C++实现深度优先搜索DFS(附完整源码)

    C++实现深度优先搜索DFS C++实现深度优先搜索DFS完整源码(定义,实现,main函数测试) C++实现深度优先搜索DFS完整源码(定义,实现,main函数测试) #include <al ...

  3. C++用stack实现深度优先搜索DFS(附完整源码)

    C++用stack实现深度优先搜索DFS的实现 C++用stack实现深度优先搜索DFS的完整源码(定义,实现,main函数测试) C++用stack实现深度优先搜索DFS的完整源码(定义,实现,ma ...

  4. 深度优先搜索(DFS) 总结(算法+剪枝+优化总结)

    深度优先搜索(DFS) 总结(算法+剪枝+优化总结) 本文中会引用部分实例.文献资料来自不同的作者之手,由于资料整理比较困难,转载地址不在文中列举.如有侵权请联系我更换或删除!对于提供题解思路的各位大 ...

  5. 【算法很美】深入递归 (下)深度优先搜索DFS问题

    深搜.回溯.剪枝 深度优先搜索DFS 2.1 无死角搜索I 数独游戏 部分和 水洼数目 2.2 回溯和剪枝 n皇后问题 素数环 困难的串 小结 一些使用 2.1 无死角搜索I 数独游戏 你一定听说过& ...

  6. 【算法入门】深度优先搜索(DFS)

    深度优先搜索(DFS) [算法入门] 郭志伟@SYSU:raphealguo(at)qq.com 2012/05/12 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍 ...

  7. matlab bfs函数,matlab练习程序(广度优先搜索BFS、深度优先搜索DFS)

    如此经典的算法竟一直没有单独的实现过,真是遗憾啊. 广度优先搜索在过去实现的二值图像连通区域标记和prim最小生成树算法时已经无意识的用到了,深度优先搜索倒是没用过. 这次单独的将两个算法实现出来,因 ...

  8. 【数据结构与算法】2.深度优先搜索DFS、广度优先搜索BFS

    原文链接:https://blog.csdn.net/qq_41681241/article/details/81432634 总结 一般来说,广搜常用于找单一的最短路线,或者是规模小的路径搜索,它的 ...

  9. 树的广度优先搜索(BFS),深度优先搜索(DFS)

    BFS:Breadth First Search,广度优先搜索 DFS:Depth First Search,深度优先搜索 如图,A节点的下一级元素为B节点和C节点,B节点的下一级元素为D节点和E节点 ...

最新文章

  1. angular4 下载文件 Excel zip包
  2. Nature子刊 | 研究人员提出神经脆性可作为癫痫发作区(SOZ)的脑电图(EEG)标志物
  3. php 系统日志,PHP中把错误日志保存在系统日志中(Windows系统)
  4. 《Cracking the Coding Interview》——第16章:线程与锁——题目3
  5. PythonWeb仿51edu项目实战篇视频教程教学视频
  6. 2020邮箱账号密码大全_通知 | 复旦大学2020年春季学期研究生选课FAQ
  7. 写游戏软件要学什么_为什么要写关于您所知道的(或所学到的)的内容
  8. 万亿级新基建战场,阿里云的安全“防线”
  9. java框架_这篇让你吃透Java集合框架!
  10. 如何将zipoutputstream返回_嫦娥五号返回器要“跳”一下再回地球!这一“跳”大有讲究...
  11. 即时获取最新全国省市区县地图json数据(亲测可用)以及echarts中使用中国地图
  12. gtool:操作genotype data的利器
  13. PS纯色图标更换颜色
  14. 《Adaptive Unimodal Cost Volume Filtering for Deep Stereo Matching》
  15. 涨薪申请多次被拒,去年我带的实习生,今年工资比我还高1K,当天就裸辞走了.....
  16. JavaScript自定义tirm方法
  17. MATLAB画三维墨西哥草帽图,数字图像处理之图像分割-20210401063921.ppt-原创力文档...
  18. 10分钟在服务器上搭建WordPress
  19. CSDN日报191105:2019年11月全国程序员工资统计,区块链工程师比算法工资高
  20. MATLAB 基础知识 数据类型 元胞数组 创建元胞数组

热门文章

  1. Halcon之单相机标定
  2. Antimalware Service Executable 彻底关闭 没有繁琐的操作,一步到位,亲测有效!!!
  3. pms输变电状态监测_输变电设备状态监测系统(国网电科院).pdf
  4. 生物计算机是未来型计算机吗,未来的新型计算机就是指生物计算机、量子计算机和光计算机。...
  5. Codeforces Round #566 (Div. 2)-E. Product Oriented Recurrence
  6. Antd多文件上传后台接收为null问题
  7. LInux 开机启动之MBR引导
  8. 高速数据采集卡如何在高速下进行采集
  9. 算极化率的格林函数算法
  10. 2022-2028全球与中国制药二次包装设备市场现状及未来发展趋势