广度优先和深度优先搜索

前言

看着这两个搜索的前提的是读者具备图这一数据结构的基本知识,这些可以直接百度一波就了解了。图也像树一样,遍历具有很多的学问在里面,下面我将借用leetcode的题目讲解一下,虽然是图的遍历,但是借助树好像讲的更见浅白一点,不好的地方多指教。

广度优先搜索(BFS)

-对于树而言,就是一种层层遍历的感觉,在实现的过程中,常常借助的是辅助队列来实现,也就是借助先进先出的特性来实现的。下图来看。用BFS的话,就是3-9-20-15-7的结果。

整体实现来说,就是遍历root再来遍历左右子树,不过与DFS区别的是,这里是借助先进先出的特点,也就是要将前面的先排列出来,不用走到叶子结点才输出。一句话简单来说,BFS就是队列,入队列,出队列;

下面是借助leetcode的题目来巩固这个知识点,上面的图也是这个题的。题目要求层层从左往右遍历结点。

  1. class Solution {
  2. public int[] levelOrder(TreeNode root) {
  3. //特殊情况
  4. if(root == null){
  5. return new int[0];
  6. }
  7. //用队列来实现广度优先搜索
  8. ArrayList<Integer> list = new ArrayList<>();
  9. Queue<TreeNode> queue = new LinkedList<>();
  10. queue.add(root);
  11. while(!queue.isEmpty()){
  12. // 出列,这里的顺序就是先进先出,层层逐个遍历
  13. TreeNode node = queue.poll();
  14. list.add(node.val);
  15. // 逐个入列,辅助队列也是BFS的关键点
  16. if(node.left != null){
  17. queue.add(node.left);
  18. }
  19. if(node.right != null){
  20. queue.add(node.right);
  21. }
  22. }
  23. // 这样转换会慢一点
  24. // int[] res = list.stream().mapToInt(Integer::valueOf).toArray();
  25. int[] res = new int[list.size()];
  26. for(int i = 0; i < list.size();i++){
  27. res[i] = list.get(i);
  28. }
  29. //题目要求返回的是int[]
  30. return res;
  31. }
  32. }
  33. }

上面这道可以变形成输出结果不一样,也就是剑指offer中的后面两道-面试题31 - II. 从上到下打印二叉树和面试32题。

31题是要求输出的结果是不同数组的集合,每层的结点作为一个数组,解决代码如下

  1. class Solution {
  2. List<List<Integer>> res = new LinkedList<>();
  3. public List<List<Integer>> levelOrder(TreeNode root) {
  4. if(root == null){
  5. return res;
  6. }
  7. //用队列来实现广度优先搜索
  8. Queue<TreeNode> queue = new LinkedList<>();
  9. queue.add(root);
  10. while(!queue.isEmpty()){
  11. ArrayList<Integer> list = new ArrayList<>();
  12. //用队列的长度来做,这里在for循环中,长度一直在变,所以要先将其取出来
  13. //关键点:主要思想在于用每次的队列长度来 判定这一层的结点有多少
  14. //正如一开始只有一个根结点,所以长度等于一,只需执行一次添加list
  15. int size = queue.size();
  16. for(int i = 0; i < size; i++){
  17. // 出列,这里的顺序就是先进先出,层层逐个遍历
  18. TreeNode node = queue.poll();
  19. //这道题要求每层出一个数组
  20. list.add(node.val);
  21. // 逐个入列,辅助队列也是BFS的关键点
  22. if(node.left != null){ queue.add(node.left);}
  23. if(node.right != null){queue.add(node.right);}
  24. }
  25. //每层加完就添加到结果里面
  26. res.add(list);
  27. }
  28. //题目要求返回的是List<List<>>
  29. return res;
  30. }
  31. }

32题有和上面不一样的地方在于,第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。就是奇数偶数层不一样的遍历方式。可以通过借助一个布尔常量来实现。

  1. class Solution {
  2. List<List<Integer>> res = new LinkedList<>();
  3. public List<List<Integer>> levelOrder(TreeNode root) {
  4. if(root == null){
  5. return res;
  6. }
  7. //用队列来实现广度优先搜索
  8. Queue<TreeNode> queue = new LinkedList<>();
  9. queue.add(root);
  10. boolean flag = true;
  11. while(!queue.isEmpty()){
  12. //这道题有实现头插法,为了高效,使用链表数组
  13. List<Integer> list = new LinkedList<>();
  14. //用队列的长度来做,这里在for循环中,长度一直在变,所以要先将其取出来
  15. int size = queue.size();
  16. for(int i = 0; i < size; i++){
  17. // 出列,这里的顺序就是先进先出,层层逐个遍历
  18. TreeNode node = queue.poll();
  19. //关键点:这道题要求每层出一个数组,而且奇数行和偶数不一样
  20. //奇数行是从左往右,偶数行是从右往左走
  21. //借助一个布尔类型来完成
  22. if(flag){
  23. list.add(node.val);
  24. }else{
  25. //前面开始插
  26. list.add(0,node.val);
  27. }
  28. // 逐个入列,辅助队列也是BFS的关键点
  29. if(node.left != null){ queue.add(node.left);}
  30. if(node.right != null){queue.add(node.right);}
  31. }
  32. //每次遍历完一行便开始更换布尔类型
  33. flag = !flag;
  34. //每层加完就添加到结果里面
  35. res.add(list);
  36. }
  37. //题目要求返回的是List<List<>>a
  38. return res;
  39. }
  40. }

深度优先搜索DFS

讲到DFS,很容易想到递归,没错它就是借助了递归的思想。在图中的描述是:深度优先搜索在搜索过程中访问某个顶点后,需要递归地访问此顶点的所有未访问过的相邻顶点

上面的图即是该题,题目要求输入一个目标sum,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

  1. 比如给出22,则返回下面
  2. {
  3. [5,4,11,2],
  4. [5,8,4,5]
  5. }
  1. /**
  2. leetcode 二叉树中和为某一值的路径(剑指offer34题)
  3. * Definition for a binary tree node.
  4. * public class TreeNode {
  5. * int val;
  6. * TreeNode left;
  7. * TreeNode right;
  8. * TreeNode(int x) { val = x; }
  9. * }
  10. */
  11. class Solution {
  12. LinkedList<List<Integer>> res = new LinkedList<>();
  13. LinkedList<Integer> path = new LinkedList<>();
  14. public List<List<Integer>> pathSum(TreeNode root, int sum) {
  15. // 有遍历 有递归
  16. recur(root,sum);
  17. //返回的是链表的链表结果
  18. return res;
  19. }
  20. public void recur(TreeNode root,int sum){
  21. // 递归的终止条件
  22. if (root == null){
  23. return;
  24. }
  25. path.add(root.val);
  26. sum -= root.val;
  27. //找到了最后叶子结点,且可以满足sum的和要求,便将该结果添加进去res
  28. if (sum == 0&& root.left ==null&&root.right == null){
  29. //这里需要添加新的对象
  30. res.add(new LinkedList<>(path));
  31. }
  32. // 左子树递归
  33. recur(root.left,sum);
  34. // 右子树递归
  35. recur(root.right,sum);
  36. // 删掉上一个结点,这一步是比较难理解的,这一步有点回溯的感觉,就是你找到最后不符合要求的结点,你要返回到上一步,重新走下去。这一步是左右子树都递归完成后就会执行的
  37. path.removeLast();
  38. }
  39. }

最后

这里的DFS还没讲完,只是单纯讲了这一道,后面再补上一些题目来写。

补上一道

leetcode104-求深度

这个题是要求求树的深度,可以很好得对比BFS和DFS的做法,实例如下。

直接上代码,格式和模板都和上面的差不多。

  1. public int maxDepth(TreeNode root) {
  2. // bfs
  3. //时间复杂度也为O(n)
  4. if(root == null){
  5. return 0;
  6. }
  7. Queue<TreeNode> queue = new LinkedList<>();
  8. queue.add(root);
  9. int num = 0;
  10. while(!queue.isEmpty()){
  11. num++;
  12. //借助队列来完成
  13. int size = queue.size();
  14. for(int i = 0; i < size; i++){
  15. TreeNode node = queue.poll();
  16. if(node.left != null){
  17. queue.add(node.left);
  18. }
  19. if(node.right != null){
  20. queue.add(node.right);
  21. }
  22. }
  23. }
  24. return num;
  25. }
  26. //Dfs 只有这两行。
  27. // 时间复杂度为O(n),
  28. if(root == null){
  29. return 0;
  30. }else{
  31. return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
  32. }

借助leetcode题目来了解BFS和DFS的更多相关文章

  1. 449. Serialize and Deserialize BST——几乎所有树的面试题目都会回到BFS或者DFS,使用BFS,None节点存#

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  2. 算法基础:BFS和DFS的直观解释

    算法基础:BFS和DFS的直观解释 https://cuijiahua.com/blog/2018/01/alogrithm_10.html 一.前言 我们首次接触 BFS 和 DFS 时,应该是在数 ...

  3. 拓扑排序(附LeetCode题目)

    算法期中考到一题关于拓扑序的题目,觉得很值得一写. 1.什么是拓扑序? 对一个有向无环图进行拓扑排序,假如图中存在一条从顶点A到顶点B的路径,则拓扑序中顶点A出现在顶点B的前面.要注意的是,这是对有向 ...

  4. leetcode题目清单

    2016-09-24,开始刷leetcode上的算法题,下面整理一下leetcode题目清单.Github-leetcode 1.基本数学 Two Sum Palindrome Number Cont ...

  5. HDU-4607 Park Visit bfs | DP | dfs

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 首先考虑找一条最长链长度k,如果m<=k+1,那么答案就是m.如果m>k+1,那么最 ...

  6. BFS和DFS详解

    BFS和DFS详解以及java实现 前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问 ...

  7. 算法录 之 BFS和DFS

    说一下BFS和DFS,这是个比较重要的概念,是很多很多算法的基础. 不过在说这个之前需要先说一下图和树,当然这里的图不是自拍的图片了,树也不是能结苹果的树了.这里要说的是图论和数学里面的概念. 以上概 ...

  8. BFS、DFS、先序、中序、后序遍历的非递归算法(java)

    一 广度优先遍历(BFS) //广度优先遍历二叉树,借助队列,queue public static void bfs(TreeNode root){ Queue<TreeNode> qu ...

  9. BFS和DFS算法

    昨晚刚昨晚华为笔试题,用到了BFS和DFS,可惜自己学艺不精,忘记了实现原理,现在借用大佬写的内容给自己做个提高 转自:https://www.jianshu.com/p/70952b51f0c8 图 ...

随机推荐

  1. Arcgis License的安装及破解

    1.双击LicenseManager安装目录下的Setup.exe. 2.点击“Next”. 3.选择“I accept the license agreement”,点击“Next”. 4.点击“C ...

  2. File.Create(path)未关闭遇到的一点点问题

    本人老菜鸟一枚,不是因为偶是菜鸟中的老手,而是偶是老了但是还是很菜的鸟╮(╯▽╰)╭,不过打今儿起偶想要腾飞…… 今天写文本文件编辑类时遇到一个小问题,下面先将问题描述一下: 1.写文本文件时都会习惯 ...

  3. flex布局你真的搞懂了吗?通俗简洁,小白勿入~

    flex布局 用以代替浮动的布局手段: 必须先把一个元素设置为弹性容器://display:flex: 一个元素可以同时是弹性容器和弹性元素; 设为flex布局以后,子元素的float.clear和v ...

  4. C++中的各种进制转换函数汇总

    C++中的各种进制转换函数汇总 1.在C中,按指定进制格式输出如下: #include <iostream> #include <cstdio> using namespace ...

  5. idea运行javadoc生成文档以及 报错编码gbk的不可映射字符坑

    将项目类信息生成文档 idea整合了javadoc的操作,可以一键生成doc文档 方法: 选中你要生成文档的项目 点击上方tools->Generate JavaDoc 运行即可 注意这里有一个 ...

  6. Ali_Cloud++:阿里云部署 Jenkins持续集成自动化部署

    安装方式: 1.yum 源安装 rpm包 2.结合 tomcat 使用 war包 ....... 下载地址:Dowlnoad  (分:长期支持版本 (LTS)  和  每周更新版) jenkins插件 ...

  7. html5 css写出一个实心三角形和空心三角行

    原理:css中的border属性的特殊性. 实心三角形: html5: <div id="mydiv"></div> css: #mydiv{ height ...

  8. 1006 Sign In and Sign Out (25 分)

    At the beginning of every day, the first person who signs in the computer room will unlock the door, ...

  9. python之excel的封装

    python之excel的封装 将所有excel的操作都使用面向对象的思维进行封装,即将所有操作都放入一个类中即为封装. 它将excel的处理极大程度的进行了简化操作 封装前需要先处理的操作: 1.在 ...

  10. 【PHP】PHP运算符

    一.      概论: a)    在数学中的运算符和PHP当中的运算符可能有一些小小的区别,但是区别 不打,都是用来做计算的:唯一的区别是,PHP当中的运算符分类比较多 二.      PHP当中运 ...