BFS(广度优先搜索)——搜索算法

        BFS,也就是广度(宽度)优先搜索,二叉树的层序遍历就是一个BFS的过程。而前、中、后序遍历则是DFS(深度优先搜索)。从字面意思也很好理解,DFS就是一条路走到黑,BFS则是一层一层地展开。

关于二叉树的创建与遍历,大家可以参考下文:

二叉树创建和遍历_二叉树的建立与遍历-CSDN博客

下图分别是DFS和BFS的遍历顺序图解: 

    

一、层序遍历

接下来我们直接来看题,从题中感受BFS的魅力。

        N叉树与二叉树的区别无非就是二叉树最多只有两个子节点用left和right两个指针就够储存。而N叉树有N多个节点,需要一个指针数组来储存

在用BFS解决问题时几乎都要借助队列结构,用队列的先进先出特性来储存上一层的数据。

        首先把根节点放到队列里面,然后从队列里面取节点出来,把节点取出来后,通过它找到它的子节点并带入到队列里面。那么这个节点的使命就算完成了,需要把它踢出队列。循环往复直到最后队列为空,则完成层序遍历。

        但对于这个题并不是简单的层序遍历就行,它还要把每一层划分出来。这个其实也很简单,只要记录每一层有几个节点(记为n个),然后一次性的遍历n个,并把这n个元素用数组储存起来。可以直接使用size()计算该层元素个数。

代码示例:

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root)
    {
        if(!root) return {};
        vector<vector<int>> ret;
        queue<Node*> qu;
        qu.push(root);
        while(!qu.empty())
        {
            vector<int> arr;
            int n=qu.size();//获取该层有一个元素
            while(n--)//取出该层的所以元素并把子节点带入
            {
                Node* rt=qu.front();
                qu.pop();
                arr.push_back(rt->val);
                for(int i=0;i<rt->children.size();i++)
                    qu.push(rt->children[i]);
            }
            if(!arr.empty()) ret.push_back(arr);
        }    
        return ret;
    }
};

二、最短路问题

例如我们要找到从起点(1)到终点(8)的最短路径。

最终找到最短路如下: 

例题:

首先因为它是上下左右式的扩散,所以使用一个小技巧:向量坐标

dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};

我们使用

for(int k=0;k<4;k++)

        x1 = x+dx[k], y1 = y+dy[k];

就可以得到(x, y)的上下左右坐标的(x1, y1)。

        它的扩展逻辑就和上文层序遍历中那一题差不多,但需要一个变量记录层数。在扩展过程中需要判断是否是目标值,还需要把扩展到的元素做标记

代码示例:

class Solution {
public:
    int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
    int nearestExit(vector<vector<char>>& maze, vector<int>& entrance)
    {
        int n = maze.size(),m = maze[0].size();
        vector<vector<bool>> hash(n,vector<bool>(m));//记录是否已经搜索过
        queue<pair<int,int>> qu;
        qu.push({entrance[0],entrance[1]});
        hash[entrance[0]][entrance[1]] = true;
        int ret = 0;//记录层数
        while(!qu.empty())
        {
            ret++;
            int sz = qu.size();
            while(sz--)
            {
                auto [a,b] = qu.front();
                qu.pop();
                for(int k=0;k<4;k++)
                {
                    int x = a+dx[k],y = b+dy[k];
                    if(x>=0&&x<n&&y>=0&&y<m&&!hash[x][y]&&maze[x][y]=='.')
                    {
                        if(x==0||x==n-1||y==0||y==m-1) return ret;
                        hash[x][y] = true;
                        qu.push({x,y});
                    }
                }
            }
        }
        return -1;
    }
};

        这个题我们可以做一个多趟的BFS,首先确定第一个起点和终点,进行BFS搜索并记录路径长度。

        注意:由题可知没有两棵树的高度是相同的,也就是说树的高度和它的坐标是一一对应的

具体操作如下:

        把所有树的高度(>1的元素)都记录到一个数组中,然后对该数组进行排序。这样我们就知道搜索的先后顺序。

        封装一个bfs函数,如pair<int,int> bfs(int x,int y,int target,vector<vector<int>>& forest),传入起点坐标与终点的值,它的作用是记录起点到终点的最短距离,然后返回终点的坐标。如果不能被搜索到返回{-1, -1}。

        距离的计算我们可以使用一个全局变量在bfs中累加。

        进行一次bfs后得到的返回值作为下一次搜索的起点下标,而终点值从刚才排序好的数组中取到。

        最后,使用循环把数组中所有的值都搜索一遍。

class Solution {
public:
    int ret = 0,m = 0,n = 0;
    int dx[4] = {0,0,-1,1},dy[4]={-1,1,0,0};
    int cutOffTree(vector<vector<int>>& forest)
    {
        m = forest.size(),n = forest[0].size();
        vector<int> arr;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                if(forest[i][j]>1) arr.push_back(forest[i][j]);
        sort(arr.begin(),arr.end());
        int x = 0,y = 0;
        for(int i=0;i<arr.size();i++)
        {
            if(i==0&&arr[i]==forest[0][0]) continue;
            auto [a,b] = bfs(x,y,arr[i],forest);
            if(a==-1) return -1;
            x = a,y = b;
        }
        return ret;
    }
    pair<int,int> bfs(int x,int y,int target,vector<vector<int>>& forest)
    {
        vector<vector<bool>> hash(m,vector<bool>(n));
        queue<pair<int,int>> qu;
        qu.push({x,y});
        hash[x][y] = true;
        while(!qu.empty())
        {
            ret++;
            int sz = qu.size();
            while(sz--)
            {
                auto [a,b] = qu.front();
                qu.pop();
                for(int k=0;k<4;k++)
                {
                    int x1 = a+dx[k],y1 = b+dy[k];
                    if(x1>=0&&x1<m&&y1>=0&&y1<n&&!hash[x1][y1]&&forest[x1][y1]!=0)
                    {
                        if(forest[x1][y1]==target) return {x1,y1};
                        hash[x1][y1]=true;
                        qu.push({x1,y1});
                    }
                }
            }
        }
        return {-1,-1};
    }
};

三、多源最短路问题

多源最短路它的特点就是可以选择多个起点,找出到达终点的最短路径。

        其实它和单源最短路差别并不是很大,我们只需要把所有起点看作一个整体,也就是把它当作“超级源点”那么它就是一个单源最短路问题。

        这个题很明显我们可以使用BFS解决,但是如果每个1的位置都用一次BFS搜索,未免也太麻烦,那么我们可以用多源最短路的思想,把所有0当作起点,然后去搜索1并填充最短路径。                那么为什么不用所有的1为起点去搜索0呢,因为我们需要填写的信息是1的位置,如果用1去搜索0的话,最后就不能找到原来那个1的位置。 

代码示例:

class Solution {
public:
    int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat)
    {
        int m=mat.size(),n=mat[0].size();
        vector<vector<int>> ret(m,vector<int>(n,-1));//充当了哈希表的功能
        queue<pair<int,int>> q;
        for(int i=0;i<m;i++)//把所有起点加入队列中
        {
            for(int j=0;j<n;j++)
            {
                if(mat[i][j]==0)
                {
                    q.push({i,j});
                    ret[i][j]=0;
                }
            }
        }
        int tmp = 0;
        while(!q.empty())
        {
            tmp++;
            int sz = q.size();
            while(sz--)
            {
                auto [i,j]=q.front();
                q.pop();
                for(int k=0;k<4;k++)
                {
                    int x=dx[k]+i,y=dy[k]+j;
                    if(x>=0&&x<m&&y>=0&&y<n&&ret[x][y]==-1)
                    {
                        ret[x][y]=tmp;
                        q.push({x,y});
                    }
                }
            }
        }
        return ret;
    }
};

四、拓扑排序问题

在一个有向无环图中,要保证在 “被指向的节点” 出现之前,它的 “父节点” 要先出现。

通常用顶点来表示一个活动,用边的指向来表示活动之间的先后顺序。如:

如上,拓扑排序的结果可能有多种,只要合法就行。

排序方法:

  • 1.记录每个顶点的入度边个数,和出度边的指向。
  • 2.把所有入度边为0的节顶点push到队列中。
  • 3.拿出队头元素加入到结果中。
  • 4.把该元素指向的所有顶点入度边减1,并判断如果有顶点的入度边为0则push到队列。
  • 循环执行3,4部直到队列为空,则完成排序。

210. 课程表 II - 力扣(LeetCode)

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        vector<int> in(numCourses), ret;
        vector<vector<int>> out(numCourses);
        for(int i=0;i<prerequisites.size();i++)
        {
            int a=prerequisites[i][0];
            int b=prerequisites[i][1];
            in[a]++;
            out[b].push_back(a);
        }    
        queue<int> q;
        for(int i=0;i<numCourses;i++)
            if(in[i]==0) q.push(i);
        while(!q.empty())
        {
            int v = q.front();
            ret.push_back(v);
            q.pop();
            for(int i=0;i<out[v].size();i++)
                if(--in[out[v][i]]==0) q.push(out[v][i]);
        }
        if(ret.size()!=numCourses) return {};
        return ret;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963894.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloud基础二(完结)

HTTP客户端Feign 在SpringCloud基础一中&#xff0c;我们利用RestTemplate结合服务注册与发现来发起远程调用的代码如下&#xff1a; String url "http://userservice/user/" order.getUserId(); User user restTemplate.getForObject(url, User.class);以上代码就…

Spring Bean 容器

技术成长&#xff0c;是对场景设计细节不断的雕刻&#xff01; 你觉得自己的技术什么时候得到了快速的提高&#xff0c;是CRUD写的多了以后吗&#xff1f;想都不要想&#xff0c;绝对不可能&#xff01;CRUD写的再多也只是能满足你作为一个搬砖工具人&#xff0c;敲击少逻辑流…

【react+redux】 react使用redux相关内容

首先说一下&#xff0c;文章中所提及的内容都是我自己的个人理解&#xff0c;是我理逻辑的时候&#xff0c;自我说服的方式&#xff0c;如果有问题有补充欢迎在评论区指出。 一、场景描述 为什么在react里面要使用redux&#xff0c;我的理解是因为想要使组件之间的通信更便捷…

利用腾讯云cloud studio云端免费部署deepseek-R1

1. cloud studio 1.1 cloud studio介绍 Cloud Studio&#xff08;云端 IDE&#xff09;是基于浏览器的集成式开发环境&#xff0c;为开发者提供了一个稳定的云端工作站。支持CPU与GPU的访问。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器即可使用。Clo…

基于VMware的ubuntu与vscode建立ssh连接

1.首先安装openssh服务 sudo apt update sudo apt install openssh-server -y 2.启动并检查ssh服务状态 到这里可以按q退出 之后输入命令 &#xff1a; ip a 红色挡住的部分就是我们要的地址&#xff0c;这里就不展示了哈 3.配置vscode 打开vscode 搜索并安装&#xff1a;…

四川正熠法律咨询有限公司正规吗可信吗?

在纷繁复杂的法律环境中&#xff0c;寻找一家值得信赖的法律服务机构是每一个企业和个人不可或缺的需求。四川正熠法律咨询有限公司&#xff0c;作为西南地区备受瞩目的法律服务提供者&#xff0c;以其专注、专业和高效的法律服务&#xff0c;成为众多客户心中的首选。 正熠法…

【优先算法】专题——位运算

在讲解位运算之前我们来总结一下常见的位运算 一、常见的位运算 1.基础为运算 << &&#xff1a;有0就是0 >> |&#xff1a;有1就是1 ~ ^&#xff1a;相同为0&#xff0c;相异位1 /无进位相加 2.给一个数 n&#xff0c;确定它的二进制表示…

Android --- handler详解

handler 理解 handler 是一套Android 消息传递机制&#xff0c;主要用于线程间通信。 tips&#xff1a; binder/socket 用于进程间通信。 参考&#xff1a; Android 进程间通信-CSDN博客 handler 就是主线程在起了一个子线程&#xff0c;子线程运行并生成message &#xff0c;l…

【线程】基于阻塞队列的生产者消费者模型

文章目录 1 生产者消费者模型2 阻塞队列2.1 成员变量2.2 消费者操作2.3 生产者生产 3 总结 1 生产者消费者模型 在多线程环境中&#xff0c;生产者消费者模型是一种经典的线程同步模型&#xff0c;用于处理生产者线程与消费者线程之间的工作调度和资源共享问题。在这个模型中&a…

解决PyG安装中torch-sparse安装失败问题:详细指南

1 问题描述 最近在学习GNN&#xff0c;需要使用PyTorch Geometric&#xff08;PyG&#xff09;库。在安装PyG的过程中&#xff0c;遇到了torch-sparse安装失败的问题&#xff0c;错误提示为&#xff1a; ERROR: Failed building wheel for torch-sparse本文将详细记录问题的解…

4 [危机13小时追踪一场GitHub投毒事件]

事件概要 自北京时间 2024.12.4 晚间6点起&#xff0c; GitHub 上不断出现“幽灵仓库”&#xff0c;仓库中没有任何代码&#xff0c;只有诱导性的病毒文件。当天&#xff0c;他们成为了 GitHub 上 star 增速最快的仓库。超过 180 个虚假僵尸账户正在传播病毒&#xff0c;等待不…

【B站保姆级视频教程:Jetson配置YOLOv11环境(六)PyTorchTorchvision安装】

Jetson配置YOLOv11环境&#xff08;6&#xff09;PyTorch&Torchvision安装 文章目录 1. 安装PyTorch1.1安装依赖项1.2 下载torch wheel 安装包1.3 安装 2. 安装torchvisiion2.1 安装依赖2.2 编译安装torchvision2.2.1 Torchvisiion版本选择2.2.2 下载torchvisiion到Downloa…

自动化软件测试的基本流程

一、自动化测试的准备 1.1 了解测试系统 首先对于需要测试的系统我们需要按照软件需求说明书明确软件功能。这里以智慧养老系统作为案例进行测试&#xff0c;先让我们看看该系统的登录界面和用户管理界面。 登录界面&#xff1a; 登录成功默认界面&#xff1a; 用户管理界面…

前端力扣刷题 | 6:hot100之 矩阵

73. 矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 法一&#xff1a; var setZeroes function(matrix) {let setX new Set(); // 用于存储需要置零的行索引let setY new Set(); //…

SLAM技术栈 ——《视觉SLAM十四讲》学习笔记(一)

《视觉SLAM十四讲》学习笔记&#xff08;一&#xff09; 第2讲 初识SLAM习题部分 第3讲 三维空间刚体运动3.1 左手系与右手系3.2 齐次坐标3.3 旋转矩阵与变换矩阵3.4 正交群与欧式群3.5 旋转向量与欧拉角3.6 实践Eigen线性代数库3.6.1 QR分解(QR decomposition) 3.7 四元数到其…

自动驾驶---两轮自行车的自主导航

1 背景 无人驾驶汽车最早出现在DARPA的比赛中&#xff0c;从那个时刻开始&#xff0c;逐渐引起全球学者的注意&#xff0c;于是从上个世纪开始各大高校院所开始了无人汽车的研发。直到这两年&#xff0c;无人驾驶汽车才开始走进寻常百姓家&#xff0c;虽然目前市面上的乘用车还…

Spring Boot 2 快速教程:WebFlux处理流程(五)

WebFlux请求处理流程 下面是spring mvc的请求处理流程 具体步骤&#xff1a; 第一步&#xff1a;发起请求到前端控制器(DispatcherServlet) 第二步&#xff1a;前端控制器请求HandlerMapping查找 Handler &#xff08;可以根据xml配置、注解进行查找&#xff09; 匹配条件包括…

优选算法的灵动之章:双指针专题(一)

个人主页&#xff1a;手握风云 专栏&#xff1a;算法 一、双指针算法思想 双指针算法主要用于处理数组、链表等线性数据结构中的问题。它通过设置两个指针&#xff0c;在数据结构上进行遍历和操作&#xff0c;从而实现高效解决问题。 二、算法题精讲 2.1. 查找总价格为目标值…

Intel 与 Yocto 项目的深度融合:全面解析与平台对比

在嵌入式 Linux 领域&#xff0c;Yocto 项目已成为构建定制化 Linux 发行版的事实标准&#xff0c;广泛应用于不同架构的 SoC 平台。Intel 作为 x86 架构的领导者&#xff0c;在 Yocto 生态中投入了大量资源&#xff0c;为其嵌入式处理器、FPGA 和 AI 加速硬件提供了完整的支持…

算法刷题Day29:BM67 不同路径的数目(一)

题目链接 描述 解题思路&#xff1a; 二维dp数组初始化。 dp[i][0] 1, dp[0][j] 1 。因为到达第一行第一列的每个格子只能有一条路。状态转移 dp[i][j] dp[i-1][j] dp[i][j-1] 代码&#xff1a; class Solution: def uniquePaths(self , m: int, n: int) -> int: #…