BFS/DFS

树专题回溯算法中其实已经涉及到了BFS和DFS算法,这里单独提出再进一步学习一下

BFS

广度优先遍历 Breadth-First-Search

这部分的内容也主要是学习了labuladong公众号内的相关讲解

算法流程

  1. 首先将开始节点放入队列中。
  2. 从队列中取出第一个节点,并检验它是否为目标。
    • 如果找到目标,则结束搜索并回传结果。
    • 否则将它所有尚未检验过的直接子节点加入队列中。
  3. 若队列为空,表示整张图都检查过了——亦即图中没有欲搜索的目标。结束搜索并回传“找不到目标”。
  4. 重复步骤 2。

算法模版

  1. 一般模版:

    void bfs(Node start, Node target){
    // 使用双端队列,而不是数组
    Queue<TreeNode> queue = new ArrayDeque<>();
    // 注意:ArrayDeque不允许null值,LinkedList允许null值
    // Queue<TreeNode> queue = new LinkedList<>();
    // 记录层数
    int steps = 0;
    // 记录访问过的节点
    Set<Node> visited = new HashSet<>(); queue.offer(start);
    while(!queue.isEmpty()){
    // 当前层的节点数
    int size = queue.size();
    // 遍历当前层的所有节点数
    for (int i=0; i<size; i++){
    Node node = queue.poll();
    result.add(node);
    // 判断节点是否满足,而决定是否返回等操作
    if(node.val == target.val){
    return steps; // || return result;
    }
    // 将node周围的还未访问过的节点都加入队列中
    for(Node tmp: node.adj()){
    if(!visited.contains(tmp)){
    queue.offer(tmp);
    visited.add(tmp);
    }
    }
    }
    steps += 1; // 遍历完一层,层数+1
    }
    return;
    }

    相关题目:

  2. 针对树这种数据结构,因没有子节点回指向父节点的指针,因此可以不需要上述的 visited

    void bfs(TreeNode root){
    // 使用双端队列,而不是数组
    Queue<TreeNode> queue = new ArrayDeque<>();
    // 注意:ArrayDeque不允许null值,LinkedList允许null值
    // Queue<TreeNode> queue = new LinkedList<>();
    // 记录层数
    int steps = 0; queue.offer(root);
    while(!queue.isEmpty()){
    // 当前层的节点数
    int size = queue.size();
    // 遍历当前层的所有节点数
    for (int i=0; i<size; i++){
    TreeNode node = queue.poll();
    result.add(node);
    // 判断节点是否满足,而决定是否返回等操作
    if(node.left != null){
    queue.offer(node.left);
    }
    if(node.right != null){
    queue.offer(node.right);
    }
    }
    steps += 1; // 遍历完一层,层数+1
    }
    return;
    }

    典型题目:

带权最短距离

堆专题中涉及到了带权的最短距离,即此时的节点到邻居之间的距离不是定值了,而是带有权重。

使用优先队列的 BFS 实现典型的就是 dijkstra 算法。dijkstra 算法主要解决的是图中任意两点的最短距离。

算法的基本思想是贪心,每次都遍历所有邻居,并从中找到距离最小的,本质上是一种广度优先遍历。

更具体的内容跳转:堆专题-总结-四大应用-带权最短距离

DFS

深度优先遍历 Depth-First-Search,DFS,是一种用于遍历或搜索树或图的算法。

算法流程:

  1. 首先将根节点放入stack 中。
  2. stack 中取出第一个节点,并检验它是否为目标。如果找到所有的节点,则结束搜寻并回传结果。否则将它某一个尚未检验过的直接子节点加入stack中。
  3. 重复步骤 2。
  4. 如果不存在未检测过的直接子节点。将上一级节点加入stack中,重复步骤 2。
  5. 重复步骤 4。
  6. stack为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”。

这里的 stack 可以理解为自己实现的栈,也可以理解为调用栈。如果是调用栈的时候就是递归,如果是自己实现的栈的话就是迭代。

算法模版

一个典型的通用的 DFS 模板可能是这样的:

boolean[] visited;
void dfs(int i) {
if (满足特定条件){
// 返回结果 or 退出搜索空间
} visited[i] = true // 将当前状态标为已搜索
for (根据i能到达的下个状态j) {
if (!visited[j]) { // 如果状态j没有被搜索过
dfs(j)
}
}
}

这部分内容在可以参考树专题回溯算法内容

题目

752. 打开转盘锁

public int openLock(String[] deadends, String target) {

    // 记录需要跳过的死亡密码
Set<String> deads = new HashSet<>();
for(String s: deadends){
deads.add(s);
} // 记录已经穷举过的密码,防止走回头路
Set<String> visited = new HashSet<>();
// 队列
Queue<String> queue = new LinkedList<>(); // 从起点开始进行BFS
int step = 0;
queue.offer("0000");
visited.add("0000"); while(!queue.isEmpty()){
// 当前层的节点数
int size = queue.size();
// 遍历当前层的所有节点数
for(int i=0; i<size; i++){
String cur = queue.poll(); // 判断节点是否相应条件
if(deads.contains(cur)) continue;
if(cur.equals(target)) return step; // 周围的还未访问过的可能都加入队列中
for(int j=0; j<4; j++){
// 向上拨一个数字
String up = plusOne(cur, j);
if (!visited.contains(up)) {
queue.offer(up);
visited.add(up);
}
// 向下拨一个数字
String down = minusOne(cur, j);
if (!visited.contains(down)) {
queue.offer(down);
visited.add(down);
}
}
}
step += 1; // 遍历完一层,层数+1
}
// 如果穷举完都没找到目标密码,那就是找不到了
return -1;
} // 将 s[j] 向上拨动一次
private String plusOne(String s, int j) {
char[] ch = s.toCharArray();
if (ch[j] == '9')
ch[j] = '0';
else
ch[j] += 1;
return new String(ch);
}
// 将 s[i] 向下拨动一次
private String minusOne(String s, int j) {
char[] ch = s.toCharArray();
if (ch[j] == '0')
ch[j] = '9';
else
ch[j] -= 1;
return new String(ch);
}

参考:BFS 算法框架套路详解

773. 滑动谜题

public int slidingPuzzle(int[][] board) {

    /******* 准备工作 *******/
int m = 2, n = 3;
char[] start = new char[6];
char[] target = {'1', '2', '3', '4', '5', '0'}; // 将2*3转化为字符串
int index_s = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
start[index_s++] = (char)(board[i][j] + '0');
}
} // 记录一维字符串的相邻索引
List<List<Integer>> neighbor = new ArrayList<>();
neighbor.add(Arrays.asList(1, 3));
neighbor.add(Arrays.asList(0, 2, 4));
neighbor.add(Arrays.asList(1, 5));
neighbor.add(Arrays.asList(0, 4));
neighbor.add(Arrays.asList(1, 3, 5));
neighbor.add(Arrays.asList(2, 4)); /******* BFS 算法框架开始 *******/
Queue<char[]> queue = new LinkedList<>();
Set<String> visited = new HashSet<>();
queue.offer(start);
visited.add(new String(start));
int steps = 0; while(!queue.isEmpty()){
int size = queue.size();
for(int i=0; i<size; i++){
char[] cur = queue.poll(); // 判断是否达到目标局面
if(isEqual(cur, target)){
return steps;
} // 找到数字 0 的索引
int index = 0;
for(; cur[index] != '0'; index++); // 将数字 0 和相邻的数字交换位置
for(Integer adj: neighbor.get(index)){
char[] tmp = new char[6];
System.arraycopy(cur, 0, tmp, 0, 6);
swap(tmp, index, adj);
if(!visited.contains(new String(tmp))){
queue.offer(tmp);
visited.add(new String(tmp));
}
}
}
steps++;
} return -1;
} private void swap(char[] chars, int i, int j){
char tmp = chars[i];
chars[i] = chars[j];
chars[j] = tmp;
} private boolean isEqual(char[] a, char[] b){
if(a.length != b.length){
return false;
} for(int i=0; i<a.length; i++){
if(a[i] != b[i]){
return false;
}
}
return true;
}

参考:益智游戏克星:BFS暴力搜索算法

111. 二叉树的最小深度

public int minDepth(TreeNode root) {
if(root == null){
return 0;
} return bfs(root);
} private int bfs(TreeNode root){ Queue<TreeNode> queue = new LinkedList<>();
// 记录层数
int steps = 1; queue.offer(root);
while(!queue.isEmpty()){
// 当前层的节点数
int size = queue.size();
// 遍历当前层的所有节点数
for (int i=0; i<size; i++){
TreeNode node = queue.poll();
// 判断节点是否满足,而决定是否返回等操作
if(node.left == null && node.right == null){
return steps;
}
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
}
steps += 1;
} return steps;
}

LeetCode:BFS/DFS的更多相关文章

  1. 经典图算法Java代码实践:BFS,DFS以及几种最短路径算法

    public class City { String name; int id; static int idCounter = 0; public City(String name) { this.n ...

  2. 【LeetCode】BFS || DFS [2017.04.10--2017.04.17]

    [102] Binary Tree Level Order Traversal [Medium-Easy] [107] Binary Tree Level Order Traversal II [Me ...

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

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

  4. Leetcode题目200.岛屿数量(BFS+DFS+并查集-中等)

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

  5. LeetCode:二叉树剪枝【814】

    LeetCode:二叉树剪枝[814] 题目描述 给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1. 返回移除了所有不包含 1 的子树的原二叉树. ( 节点 X 的子树为 X ...

  6. 【LeetCode】BFS(共43题)

    [101]Symmetric Tree 判断一棵树是不是对称. 题解:直接递归判断了,感觉和bfs没有什么强联系,当然如果你一定要用queue改写的话,勉强也能算bfs. // 这个题目的重点是 比较 ...

  7. LeetCode:“剑指 Offer”

    LeetCode:"剑指 Offer" 刷题小菜鸡,花了几天时间做了一遍 LeetCode 上给出的 "剑指 Offer" 在此做一下记录 LeetCode主页 ...

  8. LeetCode:树专题

    树专题 参考了力扣加加对与树专题的讲解,刷了些 leetcode 题,在此做一些记录,不然没几天就没印象了 力扣加加-树专题 总结 树的定义 // Definition for a binary tr ...

  9. BFS/DFS算法介绍与实现(转)

    广度优先搜索(Breadth-First-Search)和深度优先搜索(Deep-First-Search)是搜索策略中最经常用到的两种方法,特别常用于图的搜索.其中有很多的算法都用到了这两种思想,比 ...

随机推荐

  1. CentOS管理firewalld防火墙

    1.查看防火墙某个端口是否开放 firewall-cmd --query-port=80/tcp 2.开放防火墙端口80 firewall-cmd --zone=public --add-port=8 ...

  2. Sa-Token之注解鉴权:优雅的将鉴权与业务代码分离!

    Sa-Token之注解鉴权:优雅的将鉴权与业务代码分离! Sa-Token 介绍: Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证.权限认证.Session会话.单点登录. ...

  3. Linux的基础命令(一)

    目录: 一.Linux系统基础 1.shell      2. Linux命令的分类 二.Linux命令行 1.Linux命令行提示符      2.Linux通用命令行使用格式      3.Lin ...

  4. go语言游戏服务端开发(一)——架构

    五邑隐侠,本名关健昌,12年游戏生涯. 本教程以Go语言为例.   网络游戏程序分为客户端和服务端.客户端负责图形渲染.交互和一些简单校验处理,服务端负责业务逻辑处理.数据存储. 我们开发一个游戏de ...

  5. 数据库实验sql代码 myemployees 以及mygirl

    /* Navicat Premium Data Transfer Source Server : mysql Source Server Type : MySQL Source Server Vers ...

  6. Linux上安装服务器监视工具,名为pyDash。

    pyDash – A Web Based Linux Performance Monitoring Tool 你可以通过以下命令来判断是否已安装: pip --version # Python2.x ...

  7. 《手把手教你》系列技巧篇(二十六)-java+ selenium自动化测试-浏览器操作(详细教程)

    1.简介 在Web自动化的操作中,我们通常需要使用一些方法来操作浏览器,今天就来学习一下.这一篇宏哥主要是介绍一下,在自动化测试的时候,我们常见的一些浏览器操作有哪些,宏哥将会一一介绍和讲解. 2.浏 ...

  8. python字典时间日期

    字典时间日期 学习完本篇,你将会深入掌握 字典操作. 1.如何新建一个字典 2.如何正序以及反序访问字典 3.如何更新字典元素 4.如何删除字典 日期时间操作 1.如何打印一个2021-9-20 17 ...

  9. Spring Native实战(畅快体验79毫秒启动springboot应用)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  10. ssh 执行 shell脚本执行jps时:-bash: jps: command not found

    转至: https://www.codeleading.com/article/67592908468/ 我构建了hadoop集群.我们一定会写一个shell脚本去每一个节点上去jps,查看每个节点的 ...