当前位置: 首页 > news >正文

算法.图论-BFS及其拓展

文章目录

    • 广度优先搜索简介
    • 经典bfs习题
      • 地图分析
      • 贴纸拼词
    • 01bfs解析
      • 基本过程
      • 相关习题

广度优先搜索简介

  1. bfs的特点是逐层扩散, 从源头到目标点扩散了几层, 最短路就是多少

  2. bfs的使用特征是任意两个节点的距离(权值)是相同的(无向图, 矩阵天然满足这一特点)

  3. bfs开始的时候可以是单个源头, 也可以多个源头(单源bfs, 和多源bfs)

  4. bfs进出队列的时候可以是单点弹出, 也可以是整层弹出

    如果是单点弹出的时候, 队列中存放的是当前的节点和距离源点的距离

    整层弹出则不需要, 只需要保留一个level计数就可以知道到源点的距离

  5. bfs进行时通常需要一个visit数组(一般是boolean[][])来标记已经遍历到的位置

  6. bfs的时候一个点向四个方向遍历的时候通常可以用一个move数组搞定(下面是举例)

    //建立一个全局的move数组来进行四个方向的遍历(上, 右, 下, 左)
    private static final int[] move = new int[]{-1, 0, 1, 0, -1};
    //假设下面的函数是用来进行 (i, j) 的遍历的
    private static void traversal(int i, int j, int[][] matrix, boolean[][] visit){//不用写四个if, 仅仅需要进行for循环四次就可以了int r = matrix.length;int c = matrix[0].length;for(int k = 0; k < 4; k++){int ni = i + move[k];int nj = j + move[k + 1];if(ni >= 0 && ni < r && nj >= 0 && nj < c && !visit[ni][nj]){//下一个位置不越界并且没有访问过//.....进行处理逻辑, 并最终把visit数组的这一个位置置为truevisit[ni][nj] = true;}}
    }
    
  7. bfs设计的时候有很多的剪枝的操作需要进行一定的摸索

经典bfs习题

地图分析

链接: leetcode1162.地图分析

题目简介:
在这里插入图片描述

解释一下什么是曼哈顿距离, 就是一个点到另外一个点的横坐标的差值和纵坐标的差值之和, 这与我们习惯认为的对角线距离区别开

这种距离的定义通常用于矩形的表格之中(实质上: bfs最广的应用就是矩形格之中, 因为这是一种天然的无向图)

这道题本质上是要找距离陆地最近的海洋的最远的距离, 翻译成人话就是寻找距离陆地最远的海洋, 那我们直接以陆地为源点开始进行bfs即可

我们下面给出来两种实现的方案

第一种是单点弹出的方法

    //创建一个move数组private static final int[] move = new int[]{-1, 0, 1, 0, -1};//创建一个全局的visit数组private static final int MAXM = 101;private static final boolean[][] visit = new boolean[MAXM][MAXM];//方法一: 单点弹出的方式public int maxDistance(int[][] grid) {int r = grid.length;int c = grid[0].length;int seas = 0;Queue<int[]> q = new ArrayDeque<>();//遍历一下grid数组初始化队列元素同时初始化visit数组for(int i = 0; i < r; i++){for(int j = 0; j < c; j++){if(grid[i][j] == 1){visit[i][j] = true;q.offer(new int[]{i, j, 0});}else{visit[i][j] = false;seas++;}}}//特殊条件直接返回if(seas == r * c || seas == 0){return -1;}//进行bfs的主流程int distanse = 1;while(!q.isEmpty()){int[] cur = q.poll();//向四个方向尝试扩展for(int k = 0; k < 4; k++){int nx = cur[0] + move[k];int ny = cur[1] + move[k + 1];if(nx >= 0 && nx < r && ny >= 0 && ny < c && !visit[nx][ny]){visit[nx][ny] = true;q.offer(new int[]{nx, ny, cur[2] + 1});distanse = Math.max(distanse, cur[2] + 1);}}}return distanse;}
}

第二种就是整层弹出的方法

class Solution {//创建一个move数组private static final int[] move = new int[]{-1, 0, 1, 0, -1};//创建一个全局的visit数组private static final int MAXM = 101;private static final boolean[][] visit = new boolean[MAXM][MAXM];//方法二 : 整层弹出的方式public int maxDistance(int[][] grid) {int r = grid.length;int c = grid[0].length;int seas = 0;Queue<int[]> q = new ArrayDeque<>();//遍历一下grid数组初始化队列元素同时初始化visit数组for(int i = 0; i < r; i++){for(int j = 0; j < c; j++){if(grid[i][j] == 1){visit[i][j] = true;q.offer(new int[]{i, j});}else{visit[i][j] = false;seas++;}}}//特殊条件直接返回if(seas == r * c || seas == 0){return -1;}//进行bfs的主流程int level = 0;while(!q.isEmpty()){level++;int sz = q.size();while(sz-- != 0){int[] cur = q.poll();//尝试向四个方向扩展for(int k = 0; k < 4; k++){int nx = cur[0] + move[k];int ny = cur[1] + move[k + 1];if(nx >= 0 && nx < r && ny >= 0 && ny < c && !visit[nx][ny]){q.offer(new int[]{nx, ny});visit[nx][ny] = true;}}}}return level - 1;}
}

贴纸拼词

链接: [leetcode691.贴纸拼词](. - 力扣(LeetCode))

题目描述: 在这里插入图片描述

这个题的解题思路就是, 对于目标字符串target, 我们想要使用最少的代价进行拼词,

这道题如何想到用bfs主要就是对于一个字符串

target, 我们提供的每一个词都有对应的一种展开, 如下图

图片:
在这里插入图片描述

从上面的演示过程也不难看出, 我们这个本题剪枝的关键就是对target的进行排序操作, 主要就是优先削减头部的字符

代码实现如下(重点在理解逻辑)

class Solution {public static int minStickers(String[] stickers, String target) {//首先对数组中的单词排序并进行词频统计List<int[]> times = new ArrayList<>();for(int i = 0; i < stickers.length; i++){int[] temp = new int[26];String changeStr = sort(stickers[i], temp);stickers[i] = changeStr;times.add(temp);}//排序一下target字符串int[] targetTime = new int[26];target = sort(target, targetTime);Queue<String> q = new ArrayDeque<>();HashSet<String> set = new HashSet<>();StringBuilder sp = new StringBuilder();//进行bfs的主流程q.offer(target);int level = 0;//本质上还是我们弹出的逻辑没有搞懂, 我们应该一层一层的弹出while(!q.isEmpty()){int sz = q.size();level++;while(sz-- != 0){int[] curTime = new int[26];String cur = q.poll();//统计一下当前的词频for(int i = 0; i < cur.length(); i++){curTime[cur.charAt(i) - 'a']++;}for(int i = 0; i < stickers.length; i++){if(times.get(i)[cur.charAt(0) - 'a'] != 0){String next = buildStr(curTime, times.get(i), sp);if(next.equals("")) return level;if(!set.contains(next)) {set.add(next);q.offer(next);}}}}}return -1;}//对字符串排序的方法, 顺便统计一下词频private static String sort(String s, int[] temp){char[] cs = s.toCharArray();for(char elem : cs){temp[elem - 'a']++;}Arrays.sort(cs);return String.valueOf(cs);}//生成一个新的字符串private static String buildStr(int[] curTime, int[] time, StringBuilder sp){sp.setLength(0);for(int i = 0; i < 26; i++){if(curTime[i] != 0){for(int j = 0; j < Math.max(curTime[i] - time[i], 0); j++){sp.append((char)(i + 'a'));}}}return sp.toString();}}

01bfs解析

基本过程

01bfs是一种特殊的bfs, 适用于01图找寻最短路径的情况, 01bfs时间复杂度是O(节点数量 + 边的数量) 下图是我们的实例

图片:
在这里插入图片描述

上面就是一个01bfs找寻最短路径的情况, 我们的解题的流程是固定的, 如下(正确性证明略), 主要就是双端队列结合bfs

  1. 创建一个distance表, 含义就是源点到i点的最短距离是多少

    大小就是所有的节点位置, 初始化所有点的distance[i] = Integer.MAX_VALUE

  2. 将源点加入双端队列, 并修改distance[源点] = 0

  3. 当队列不为空的时候进入循环(下面就是伪代码)

    while(!queue.isEmpty()){//弹出一个节点(弹出的时候一定从头部弹出)Node node = queue.poll();//如果这个位置就是要找的目标节点就直接返回if(node == targetNode) return distance[node];//找到这个节点去的下一个位置(可能有多个...)int next = node -> next;//weight就是这两个点之间的权值(0 or 1)int weight = 0 or 1;    if(distance[node] + weight < distance[next]){//此时说明到达next的位置可以边的更小就更新distance[next] = distance[node] + weight;//然后在队列中加入这个位置, 如果刚才的权值weight == 0, 就从头部加入, 如果是1就从尾部加入if(weight == 0){queue.offerFirst(node);}else{queue.offerLast(node);}}
    }
    

相关习题

图片: 在这里插入图片描述

链接: leetcode2290.到达角落的最小代价

其实就是01bfs的模板题

class Solution {//经典01dfs板子题private static final int[] move = new int[]{-1, 0, 1, 0, -1};public int minimumObstacles(int[][] grid) {int r = grid.length;int c = grid[0].length;//初始化一个distance数组int[][] distance = new int[r][c];for(int i = 0; i < r; i++){for(int j = 0; j < c; j++){distance[i][j] = Integer.MAX_VALUE;}}//创建一个双端队列Deque<int[]> dq = new ArrayDeque<>();dq.offer(new int[]{0, 0});distance[0][0] = 0;while(!dq.isEmpty()){int[] cur = dq.poll();//如果是目标节点if(cur[0] == r - 1 && cur[1] == c - 1) return distance[cur[0]][cur[1]];//尝试向四个方向扩展for(int k = 0; k < 4; k++){int nx = cur[0] + move[k];int ny = cur[1] + move[k + 1];if(nx >= 0 && nx < r && ny >= 0 && ny < c && distance[cur[0]][cur[1]] + grid[nx][ny] < distance[nx][ny]){distance[nx][ny] = distance[cur[0]][cur[1]] + grid[nx][ny];if(grid[nx][ny] == 0){dq.offerFirst(new int[]{nx, ny});}else{dq.offerLast(new int[]{nx, ny});}}}}return -1;}
rst(new int[]{nx, ny});}else{dq.offerLast(new int[]{nx, ny});}}}}return -1;}
}

链接: leetcode1368.箭头数组的最短代价

图片: 在这里插入图片描述

class Solution {//这个move数组的设计是比较的精巧的private static final int[][] move = {{0}, {0, 1}, {0, -1}, {1, 0}, {-1, 0}};public int minCost(int[][] grid) {int r = grid.length;int c = grid[0].length;//初始化distance数组int[][] distance = new int[r][c];for(int i = 0; i < r; i++){Arrays.fill(distance[i], Integer.MAX_VALUE);}//创建双端队列Deque<int[]> dq = new ArrayDeque<>();dq.offer(new int[]{0, 0});distance[0][0] = 0;while(!dq.isEmpty()){int[] cur = dq.poll();int x = cur[0];int y = cur[1];if(x == r - 1 && y == c - 1) return distance[x][y];for(int i = 1; i < 5; i++){int nx = x + move[i][0];int ny = y + move[i][1];int weight = i == grid[x][y] ? 0 : 1;if(nx >= 0 && nx < r && ny >= 0 && ny < c && distance[x][y] + weight < distance[nx][ny]){distance[nx][ny] = distance[x][y] + weight;if(weight == 0){dq.offerFirst(new int[]{nx, ny});}else{dq.offerLast(new int[]{nx, ny});}}}}return -1;}
}

相关文章:

算法.图论-BFS及其拓展

文章目录 广度优先搜索简介经典bfs习题地图分析贴纸拼词 01bfs解析基本过程相关习题 广度优先搜索简介 bfs的特点是逐层扩散, 从源头到目标点扩散了几层, 最短路就是多少 bfs的使用特征是任意两个节点的距离(权值)是相同的(无向图, 矩阵天然满足这一特点) bfs开始的时候可以是…...

mongodb的相关关键字说明

以下是MongoDB中一些数据库相关的关键字说明&#xff1a; 1. 数据库&#xff08;Database&#xff09; 概念 数据库是MongoDB中数据存储的最高层级容器&#xff0c;类似于关系型数据库中的数据库概念。一个MongoDB服务器实例可以包含多个数据库&#xff0c;每个数据库可以有自…...

强化学习之DDPG算法

前言&#xff1a; 在正文开始之前&#xff0c;首先给大家介绍一个不错的人工智能学习教程&#xff1a;https://www.captainbed.cn/bbs。其中包含了机器学习、深度学习、强化学习等系列教程&#xff0c;感兴趣的读者可以自行查阅。 一、算法介绍 深度确定性策略梯度 &#xff0…...

【进阶OpenCV】 (16)-- 人脸识别 -- FisherFaces算法

文章目录 FisherFaces算法一、算法原理二、算法优势与局限三、算法实现1. 图像预处理2. 创建FisherFace人脸特征识别器3. 训练模型4. 测试图像 总结 FisherFaces算法 PCA方法是EigenFaces人脸识别的核心&#xff0c;但是其具有明显的缺点&#xff0c;在操作过程中会损失许多人…...

电脑主机配置

显卡&#xff1a; 查看显卡&#xff1a;设备管理器--显示适配器 RTX4060 RTX和GTX区别&#xff1a; GTX是NVIDIA公司旧款显卡&#xff0c;RTX比GTX好但是贵 处理器CPU&#xff1a; Intel(R) Core(TM) i5-10400F CPU 2.90GHz 2.90 GHz 10400F&#xff1a;10指的是第几代…...

图书借阅小程序开源独立版

图书借阅微信小程序&#xff0c;多书馆切换模式&#xff0c;书馆一键同步图书信息&#xff0c;开通会员即可在线借书&#xff0c;一书一码书馆员工手机扫码出入库从会员到书馆每一步信息把控图书借阅小程序&#xff0c;让阅读触手可及在这个快节奏的时代&#xff0c;你是否渴望…...

flutter TextField限制中文,ios自带中文输入法变英文输入问题解决

由于业务需求&#xff0c;要限制TextField只能输入中文&#xff0c;但是测试在iOS测试机发现自带中文输入法会变英文输入问题&#xff0c;安卓没有问题&#xff0c;并且只有iOS自带输入法有问题&#xff0c;搜狗等输入法没问题。我们目前使用flutter2.5.3版本&#xff0c;高版本…...

ThreadLocal的应用场景

ThreadLocal介绍 ThreadLocal为每个线程都提供了变量的副本&#xff0c;使得每个线程访问各自独立的对象&#xff0c;这样就隔离了多个线程对数据的共享&#xff0c;使得线程安全。ThreadLocal有如下方法&#xff1a; 方法声明 描述public void set(T value)设置当前线程绑定的…...

Python--plt.errorbar学习笔记

plt.errorbar 是 Matplotlib 库中的一个函数&#xff0c;用于绘制带有误差条的图形。下面给出的代码行的详细解释&#xff1a; import numpy as np from scipy.special import kv, erfc from scipy.integrate import dblquad import matplotlib.pyplot as plt import scipy.in…...

文件信息类QFileInfo

常用方法&#xff1a; 构造函数 //参数&#xff1a;文件的绝对路径或相对路径 [explicit] QFileInfo::QFileInfo(const QString &path) 设置文件路径 可构造一个空的QFileInfo的对象&#xff0c;然后设置路径 //参数&#xff1a;文件的绝对路径或相对路径 void QFileI…...

堆排序(C++实现)

参考&#xff1a; 面试官&#xff1a;请写一个堆排序_哔哩哔哩_bilibiliC实现排序算法_c从小到大排序-CSDN博客 堆的基本概念 堆排实际上是利用堆的性质来进行排序。堆可以看做一颗完全二叉树。 堆分为两类&#xff1a; 最大堆&#xff08;大顶堆&#xff09;&#xff1a;除根…...

Qt中加入UI文件

将 UI 文件整合到 Qt 项目 使用 Qt Designer 创建 UI 文件&#xff1a; 在 Qt Creator 中使用 Qt Designer 创建 UI 文件&#xff0c;设计所需的界面。确保在设计中包含所需的控件&#xff08;如按钮、文本框等&#xff09;&#xff0c;并为每个控件设置明确的对象名称&#xf…...

Redisson使用全解

redisson使用全解——redisson官方文档注释&#xff08;上篇&#xff09;_redisson官网中文-CSDN博客 redisson使用全解——redisson官方文档注释&#xff08;中篇&#xff09;-CSDN博客 redisson使用全解——redisson官方文档注释&#xff08;下篇&#xff09;_redisson官网…...

Go4 和对 Go 的贡献

本篇内容是根据2017年4月份Go4 and Contributing to Go音频录制内容的整理与翻译, Brad Fitzpatrick 加入节目谈论成为开源 Go 的代言人、让社区参与 bug 分类、Go 的潜在未来以及其他有趣的 Go 项目和新闻。 过程中为符合中文惯用表达有适当删改, 版权归原作者所有. Erik St…...

区间动态规划

区间动态规划&#xff08;Interval DP&#xff09;是动态规划的一种重要变种&#xff0c;特别适用于解决一类具有区间性质的问题。典型的应用场景是给定一个区间&#xff0c;要求我们在满足某些条件下进行最优划分或合并。本文将从区间DP的基本思想、常见问题模型以及算法实现几…...

什么情况下需要使用电压探头

高压探头是一种专门设计用于测量高压电路或设备的探头&#xff0c;其作用是在电路测试和测量中提供安全、准确的信号捕获&#xff0c;并确保操作人员的安全。这些探头通常用于测量高压电源、变压器、电力系统、医疗设备以及其他需要处理高电压的设备或系统。 而高压差分探头差分…...

数据结构——八大排序(下)

数据结构中的八大排序算法是计算机科学领域经典的排序方法&#xff0c;它们各自具有不同的特点和适用场景。以下是这八大排序算法的详细介绍&#xff1a; 五、选择排序&#xff08;Selection Sort&#xff09; 核心思想&#xff1a;每一轮从未排序的元素中选择最小&#xff0…...

Linux系统:Ubuntu上安装Chrome浏览器

Ubuntu系统版本&#xff1a;23.04 在Ubuntu系统上安装Google Chrome浏览器&#xff0c;可以通过以下步骤进行&#xff1a; 终端输入以下命令&#xff0c;先更新软件源&#xff1a; sudo apt update 或 sudo apt upgrade终端输入以下命令&#xff0c;下载最新的Google Chrome .…...

Redis位图BitMap

一、为什么使用位图&#xff1f; 使用位图能有效实现 用户签到 等行为&#xff0c;用数据库表记录签到&#xff0c;将占用很多存储&#xff1b;但使用 位图BitMap&#xff0c;就能 大大减少存储占用 二、关于位图 本质上是String类型&#xff0c;最小长度8位&#xff08;一个字…...

YOLOv11改进策略【卷积层】| ParNet 即插即用模块 二次创新C3k2

一、本文介绍 本文记录的是利用ParNet中的基础模块优化YOLOv11的目标检测网络模型。 ParNet block是一个即插即用模块,能够在不增加深度的情况下增加感受野,更好地处理图像中的不同尺度特征,有助于网络对输入数据更全面地理解和学习,从而提升网络的特征提取能力和分类性能…...

2026上半年数据库系统工程师(软考)上午题回忆与解析(非标答版)

本文为考后回忆整理&#xff0c;非官方标准答案&#xff0c;旨在为考后对答案及下半年备考的同学提供参考。题目顺序和表述可能与原卷有出入&#xff0c;欢迎在评论区指正、补充。&#x1f4ca; 整体考情分析 刚结束的2026年上半年数据库系统工程师考试&#xff0c;上午题的风格…...

电信运营商每月处理海量工单,如何不再出错?基于AI Agent的端到端自动化解决方案

在2026年的电信行业&#xff0c;海量工单处理已不再仅仅是效率问题&#xff0c;而是合规与生存的底线。随着2026年5月20日《电信和互联网服务 基础电信企业网上营业厅服务规范》国家标准的正式实施&#xff0c;监管层对“信息透明、流程闭环、计费精准”的要求达到了前所未有的…...

AI IDE 革命:程序员正在被重新定义

很多开发者第一次使用 Cursor 的 CtrlK 或 Composer&#xff08;高级多文件编辑模式&#xff09;时&#xff0c;都会有一种强烈的、甚至让人有些脊背发凉的冲击感。 因为&#xff1a; 它已经不再是那个我们熟悉的、只能在原地等待光标落下的&#xff1a; “代码自动补全插件&am…...

PCB的常规机械通孔与HDI工艺钻孔差异

结合常规 4 层通孔 PCB&#xff08;非 HDI&#xff09; 标准制程&#xff0c;分步骤讲清钻孔时机、先后顺序&#xff0c;区分机械通孔与板件结构&#xff0c;专业且贴合工厂实际流程。一、先明确 4 层通孔板基础结构4 层板结构&#xff1a;L1 → PP 半固化片 → L2/L3&#xff…...

氘可来昔替尼常见副作用为鼻咽炎头痛及腹泻,如何应对

任何口服药物的临床价值&#xff0c;都必须在疗效与安全性的天平上找到精准的平衡点。氘可来昔替尼以PASI 75应答率的全面胜出证明了自己在银屑病治疗中的卓越地位&#xff0c;而其不良反应谱同样经过了严苛的临床验证。鼻咽炎、头痛和腹泻构成了这款药物最需关注的三大安全信号…...

NanaZip:现代Windows文件压缩问题的终极解决方案

NanaZip&#xff1a;现代Windows文件压缩问题的终极解决方案 【免费下载链接】NanaZip The 7-Zip derivative intended for the modern Windows experience 项目地址: https://gitcode.com/gh_mirrors/na/NanaZip 还在为Windows文件压缩工具界面老旧、功能单一而烦恼吗&…...

DeepSeek模型微调全链路解析:从数据准备、LoRA配置到推理部署的7大关键步骤

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek模型微调全链路概览 DeepSeek系列大语言模型&#xff08;如DeepSeek-V2、DeepSeek-Coder&#xff09;凭借其开源特性、高性能推理能力与丰富的领域适配性&#xff0c;已成为工业界与学术界微调…...

ArduPilot飞行模式实战:从代码角度看Stabilize、Acro、Loiter模式如何切换(附避坑指南)

ArduPilot飞行模式深度解析&#xff1a;从状态机到实战避坑指南 在开源飞控领域&#xff0c;ArduPilot以其强大的飞行模式系统著称。不同于普通用户只需了解模式功能&#xff0c;开发者更需要掌握模式切换的底层机制——这直接关系到飞行安全与二次开发效率。本文将带您深入Sta…...

基于BLE模块的低功耗无线遥控器设计与实现

1. 项目概述&#xff1a;基于BLE模块的无线遥控器设计与实现几年前&#xff0c;我在捣鼓智能家居时&#xff0c;一直想找一个低功耗、响应快、又能自己完全掌控的无线遥控方案。市面上的成品要么协议封闭&#xff0c;要么功耗感人&#xff0c;要么延迟高得让人着急。后来&#…...

软件测试行业的未来趋势:这3类测试将成为主流

随着数字化转型的深入推进&#xff0c;软件已经成为驱动各行业变革的核心生产力&#xff0c;从自动驾驶汽车到企业级云原生平台&#xff0c;从智慧医疗设备到工业互联网系统&#xff0c;软件的复杂度、规模和对安全性的要求都在呈指数级增长。作为软件质量保障的核心环节&#…...