摘要:本文为大家分享两个常见的搜索算法:BFS和DFS。

本文分享自华为云社区《BFS和DFS算法初探》,作者: ayin。

本次分享两个常见的搜索算法:

1.BFS 即广度优先搜索

2.DFS 即深度优先搜索

岛屿数量

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

示例 1:

11110
11010
11000
00000

输出: 1

示例 2:

11000
11000
00100
00011

输出: 3

其实我们还是比较容易想到初步解法的,即从二维网络某点出发,寻找其四周相邻的陆地,直到所有包含的点都没有相邻的陆地为止,这里可以认为已经找到了一个岛屿,其余岛屿同理可以找到。这里的关键问题是遍历岛屿的顺序,其实不难看出有两种顺序

a.

  1. 优先寻找某a节点的所有相邻位置
  2. 然后拿出一个相邻位置比如说b寻找其所有相邻位置
  3. 拿出a节点下一个相邻位置重复第2步直到a节点的相邻位置都执行过该操作
  4. 拿出b,重复1,2,3步

b.

  1. 优先寻找a节点的相邻位置比如说b
  2. 寻找b的相邻位置c
  3. 直到没有相邻位置后再返回到a的下一个相邻位置,重复1,2步

§ 方案一

我们对第一种方法进行观察:

  1. 越是接近根结点的结点将越早地遍历
  2. 思考用什么存储结构来存放我们找到的位置:我们把root的相邻位置存储到x结构中,然后取出x的某个相邻位置a,寻找其相邻位置继续存放到x中,再取出x中与root相邻的下个位置b继续寻找其相邻位置放入x中。这里我们发现我们存储x的顺序与我们处理x得到其他数据的顺序一致:先进先出(FIFO),不难得出我们可以采用队列来存储
  3. 需要一种方法避免对已经找到的位置重复访问

现在可以尝试写出实际的程序

 public int numIslands(char[][] grid) {
if (grid.length==0){
return 0;
}
Queue<Point> queue = new LinkedList<>();
int count =0;
for(int y=0;y<grid.length;y++){
for(int x=0;x<grid[0].length;x++){
// 核心部分
if(grid[y][x]=='1'){
queue.offer(new Point(x,y));
while (queue.size() != 0) {
Point nowPoint = queue.peek();
List<Point> pointList = getNearPoints(nowPoint, grid); for (Point point : pointList) {
queue.offer(point);
// 标记已经访问的位置
grid[point.y][point.x] = '2';
System.out.println(point.y * grid[0].length + point.x);
}
queue.poll();
}
count++;
}
// 核心部分
}
}

通过这个实例我们可以进一步抽象为图论中的一种算法–BFS
可以参考leetcode的动图和算法模板来加深印象

§ 方案二

同样来观察第二中方法,我们发现

  1. 优先走完一条路径直到结束
  2. 我们需要在某一路径结束后,回溯到初始位置,即存储节点位置的顺序和处理的顺序相反,即现进后出(FILO)。这里我们可以用递归或者栈来处理。

试着写出实际的程序

1.递归

 public int numIslands(char[][] grid) {
int len = 0;
Set <Integer> visited = new HashSet<>();
for (int y = 0; y < grid.length; y++) {
for (int x = 0; x < grid[0].length; x++) {
Integer node = y * grid[0].length + x;
if (!visited.contains(node)&&grid[y][x] == '1') {
visited.add(node);
DFS3(node, visited, grid);
len++;
}
}
} return len;
}
boolean DFS(Integer cur, Set<Integer> visited,char [][]grid) {
for (Integer next : getNearNodes(cur,grid[0].length,grid.length,grid)) {
if (!visited.contains(next)) {
visited.add(next);
System.out.println(next);
DFS(next,visited,grid);
}
}
return true;
}

2.栈

 boolean DFS3(Integer cur, Set<Integer> visited,char [][]grid){
Stack<Integer> nodeStack = new Stack<>();
nodeStack.push(cur);
while(!nodeStack.empty()){
Integer node = nodeStack.peek();
boolean hasNearNode = false;
for(Integer next:getNearNodes(node,grid[0].length,grid.length,grid)){
if(!visited.contains(next)){
visited.add(next);
nodeStack.push(next);
hasNearNode = true;
}
}
// 如果当前节点没有邻居则去除栈顶节点
if(!hasNearNode){
nodeStack.pop();
}
}
return true;
}

通过这个实例我们可以进一步抽象为图论中的一种算法–DFS
参考leetcode的动图和模板算法(递归和栈)来加深印象

点击关注,第一时间了解华为云新鲜技术~

分享两个常见的搜索算法:BFS和DFS的更多相关文章

  1. BFS与DFS常考算法整理

    BFS与DFS常考算法整理 Preface BFS(Breath-First Search,广度优先搜索)与DFS(Depth-First Search,深度优先搜索)是两种针对树与图数据结构的遍历或 ...

  2. 分享两个提高效率的AndroidStudio小技巧

    这次分享两个 Android Studio 的小技巧,能够有效提高效率和减少犯错,尤其是在团队协作开发中. Getter 模板修改--自动处理 null 判断 格式化代码自动整理方法位置--广度 or ...

  3. 分享一些JVM常见的面试题(转)

    出处:  分享一些JVM常见的面试题 前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 ...

  4. 分享两个你可能不知道的Java小秘密

    引言 最近LZ的工作发生了重大变化,以后博文的更新速度可能会再度回温,希望猿友们可以继续关注. 近期LZ辞掉了项目经理的工作,不过并未离开公司,是转到了基础研发部做更基础的研发,为广大技术人员服务.这 ...

  5. 移动Web开发图片自适应两种常见情况解决方案

    本文主要说的是Web中图片根据手机屏幕大小自适应居中显示,图片自适应两种常见情况解决方案.开始吧 在做配合手机客户端的Web wap页面时,发现文章对图片显示的需求有两种特别重要的情况,一是对于图集, ...

  6. jQuery ajax调用后台aspx后台文件的两种常见方法(不是ashx)

    在asp.net webForm开发中,用Jquery ajax调用aspx页面的方法常用的有两种:下面我来简单介绍一下. [WebMethod] public static string SayHe ...

  7. 【转】分享两个基于MDK IDE的调试输出技巧

    我们在STM32开发调试过程中,常常需要做些直观的输出,如果手头没有相关的设备或仪器,我们可以使用 IDE自带的工具.这里分享两个基于MDK  IDE的调试输出技巧. 一.使用其自带的逻辑分析仪查看波 ...

  8. 移动站Web开发图片自适应两种常见情况解决方案

    本文主要说的是Web中图片根据手机屏幕大小自适应居中显示,图片自适应两种常见情况解决方案.开始吧 在做配合手机客户端的Web wap页面时,发现文章对图片显示的需求有两种特别重要的情况,一是对于图集, ...

  9. Collection两个常见的集合类型: ArrayList可重复集有序 ,HashSet不可重复集

    package seday11; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; ...

  10. Androidstudio实现一个简易的加法器——分享两种方法实现(日常作业练习)

    Androidstudio实现一个简易的加法器——分享两种方法实现(日常作业练习)                                                           ...

随机推荐

  1. 鬼谷子的钱袋(lgP2320)

    主要思路:二进制拆分. 先将 \(m\) 进行二进制拆分. 注意金币总数有限,也就是说拆分后可能会多出来一组.多出来的这组如果不是 \(2^n\) 就不需要考虑了,因为不会和前面的重复. 接下来考虑重 ...

  2. RLChina2022公开课-博弈论

    纯博弈: 单纯的动机组合,离散的集合 混合博弈: 加入了概率论,以百分比的概率执行不同的的动机.,概率分布 零和博弈.合作博弈.协同博弈 扩展博弈和非完美信息 扩展博弈.贝叶斯博弈 纳什均衡 任何一位 ...

  3. python环境配置常用命令

    #安装前请更新 sudo apt-get update python -m pip install --upgrade pip #升级PIP版本 sudo apt-get install python ...

  4. 谈谈流计算中的『Exactly Once』特性

    本文翻译自 streaml.io 网站上的一篇博文:"Exactly once is NOT exactly the same" ,分析了流计算系统中常说的『Exactly Onc ...

  5. pkg-config手册

    定义 pkg-config是一款用于返回已安装库元信息的工具: (语法)概要 pkg-config [--modversion] [--help] [--print-errors] [--silenc ...

  6. Semantic Kernel 将成为通向Assistants的门户

    OpenAI 也推出了让开发者更容易使用 OpenAI API 的开发方式--Assistants API.Sam Altman 表示,市面上基于 API 构建 agent 的体验很棒.比如,Shop ...

  7. jpa用findAll((Specification<GoodsSpu>) (root, criteriaQuery, criteriaBuilder) -> {})排序

    //需要用到的包import org.springframework.data.domain.Page;import org.springframework.data.domain.PageReque ...

  8. 解决IDEA中.properties文件中文变问号(???)的问题(已解决)

    问题背景 构建SpringBoot项目时,项目结构中有一个application.properties文件.这个项目是Spring Boot一个特有的配置文件.内容如下(我写了一些日志的配置): 写到 ...

  9. 🔥🔥Java开发者的Python快速实战指南:探索向量数据库之文本搜索

    前言 如果说Python是跟随我的步伐学习的话,我觉得我在日常开发方面已经没有太大的问题了.然而,由于我没有Python开发经验,我思考着应该写些什么内容.我回想起学习Java时的学习路线,直接操作数 ...

  10. 16、strconv

    1.strconv是什么? strconv是用来处理字符串和基本类型之间的转换的 2.strconv的使用 /** * @author ly (个人博客:https://www.cnblogs.com ...