广度优先和深度优先搜索

前言

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

广度优先搜索(BFS)

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

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

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

  class Solution {
public int[] levelOrder(TreeNode root) {
//特殊情况
if(root == null){
return new int[0];
}
//用队列来实现广度优先搜索
ArrayList<Integer> list = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
// 出列,这里的顺序就是先进先出,层层逐个遍历
TreeNode node = queue.poll();
list.add(node.val);
// 逐个入列,辅助队列也是BFS的关键点
if(node.left != null){
queue.add(node.left);
}
if(node.right != null){
queue.add(node.right);
} }
// 这样转换会慢一点
// int[] res = list.stream().mapToInt(Integer::valueOf).toArray();
int[] res = new int[list.size()];
for(int i = 0; i < list.size();i++){
res[i] = list.get(i);
}
//题目要求返回的是int[]
return res; }
} }

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

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

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

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

class Solution {
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null){
return res;
}
//用队列来实现广度优先搜索
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
boolean flag = true;
while(!queue.isEmpty()){
//这道题有实现头插法,为了高效,使用链表数组
List<Integer> list = new LinkedList<>();
//用队列的长度来做,这里在for循环中,长度一直在变,所以要先将其取出来
int size = queue.size();
for(int i = 0; i < size; i++){
// 出列,这里的顺序就是先进先出,层层逐个遍历
TreeNode node = queue.poll();
//关键点:这道题要求每层出一个数组,而且奇数行和偶数不一样
//奇数行是从左往右,偶数行是从右往左走
//借助一个布尔类型来完成
if(flag){
list.add(node.val);
}else{
//前面开始插
list.add(0,node.val);
}
// 逐个入列,辅助队列也是BFS的关键点
if(node.left != null){ queue.add(node.left);}
if(node.right != null){queue.add(node.right);}
}
//每次遍历完一行便开始更换布尔类型
flag = !flag;
//每层加完就添加到结果里面
res.add(list); } //题目要求返回的是List<List<>>a
return res; }
}

深度优先搜索DFS

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

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

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

最后

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

补上一道

leetcode104-求深度

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

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

   public int maxDepth(TreeNode root) {
// bfs
//时间复杂度也为O(n)
if(root == null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int num = 0;
while(!queue.isEmpty()){
num++;
//借助队列来完成
int size = queue.size();
for(int i = 0; i < size; i++){
TreeNode node = queue.poll();
if(node.left != null){
queue.add(node.left);
}
if(node.right != null){
queue.add(node.right);
}
}
}
return num; } //Dfs 只有这两行。
// 时间复杂度为O(n),
if(root == null){
return 0;
}else{
return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}

借助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. Python python 函数参数:关键字参数

    # 关键字参数 '''关键字参数代表传入任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict ''' def student(name,sex,**keywords): print(' ...

  2. Go相关面试题目总结(日常更新)

    1.go的深拷贝与浅拷贝 深拷贝 会赋值全部的内容 内容一样但是地址不一样 修改任何一个后地址不一样 内容也会一样 changeName(h1)对象传到函数里面也是深拷贝 b := a 这是深拷贝 会 ...

  3. 关于泛型数据结构中OrderBy的使用

    形如, 1) ICollection<ImageInfo> imageInfos = new List<ImageInfoDTO>(); imageInfos = imageI ...

  4. 如何使用Rancher在OpenStack上创建K8S集群

    不可否认的是,OpenStack仍然是可行的云操作系统,并且被全世界许多互联服务提供商使用.而Rancher是业界最为广泛使用的Kubernetes管理平台,通过简洁直观的GUI集中管理企业IT中的多 ...

  5. Linux操作系统及调用接口

    Linux操作系统包含以下各子系统: 系统调用子系统:操作系统的功能调用同一入口: 进程管理子系统:对执行程序进行生命周期和资源管理: 内存管理子系统:对系统的内存进行管理.分配.回收.隔离: 文件子 ...

  6. FastJson反序列化和构造函数之间的一点小秘密

    各位看官大家下午好,FastJson想必大家都很熟悉了,很常见的Json序列化工具.今天在下要和大家分享一波FastJson反序列化和构造函数之间的一点小秘密. 下面先进入大家都深恶痛绝的做题环节.哈 ...

  7. 安装 elasticsearch For LINUX

    官网下载地址 https://www.elastic.co/cn/downloads/elasticsearch 选择版本为LINUX 当前版本为 es-7.6.2 用tar 命令解压 tar -zx ...

  8. Level Up - ICPC Southeastern Europe Contest 2019(简单DP)

    题意:Steve玩魔兽世界要做任务升两级,任务在你不同的等级给的经验不同,输入任务数量和升第一级和升第二级需要的经验,接着输入每个任务第一级完成给的经验和花费的时间.第二级级完成给的经验和花费的时间. ...

  9. 搭建mariadb数据库系统《一》

                                                                     搭建mariadb数据库系统 案例3:搭建mariadb数据库系统 3 ...

  10. Github基础使用教程 ———功能介绍

    Github基础使用手把手教程    --功能介绍 本人Github小白,刚摸索的差不多,记录一下经验,小白写出来的东西各位萌新一定看的懂啦~ 本篇内容主要针对想快速学会使用Github这个强大工具的 ...