单源广度优先搜索 (leetcode经典例题 C++实现)

news2025/7/18 20:05:26

文章目录

  • 01矩阵
  • 地图分析
  • 腐烂的橘子

深度优先搜索与广度优先搜索前情回顾:
深度搜索dfs与广度搜索bfs算法总结(c++ 例题)

本节是广度优先搜索的进阶:

01矩阵

传送门:
https://leetcode.cn/problems/01-matrix/?envType=study-plan&id=suan-fa-ru-men&plan=algorithms&plan_progress=1ophias

寻找数组中的每一个元素距离最近的零的距离。

利用广度优先搜索:

  1. 设计一个临时的数组记录状态,我们标记每一个零。
  2. 利用广度搜索把每一个零所在的坐标放入队列中,遍历队列中的每一个元素,以及其上下左右四个方向,并且依次由上一个位置的值得到当前位置的值。

我们要记录数组的每一元素距离最近的零的距离,可以发现:
0距离最近的元素就是零。
1距离最近的零可以由四周的零走一步得到,因此距离是2。

  • 我们可以利用一个标记数组将初始数组中所有的0标记为1,表示我们不需要修改它的值,0的距离就是0.
  • 标记数组默认初始化为0,因此所有非零元素在标记数组都被标记为0
  • 广度优先搜索遍历每一个位置,寻找标记数组中值为0的位置,这即是我们所需要修改的位置,我们可以通过它的上一步 +1 并且把这个值放到一个结果数组中,结果数组中的存储的元素即是最后的答案。
    在这里插入图片描述
class Solution {
private:
    const int dirX[4]{0,0,-1,1};
    const int dirY[4]{-1,1,0,0};
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int nr=mat.size(),nc=mat[0].size();
        //1. 标记数组
        vector<vector<int>> fg_mat(nr,vector<int>(nc));
        //2. 结果数组
        vector<vector<int>> dst(nr,vector<int>(nc));
        //3. 队列:广度优先搜索
        queue<pair<int,int>> q;
        //4. 预处理: 把所有的0标记为1,代表不需要管0元素的位置,但是我们要从这里开始进行广度优先搜索
        for (int i=0;i<nr;i++)
        {
            for (int j=0;j<nc;j++)
            {
                if (mat[i][j]==0)
                {
                    q.emplace(i,j);
                    fg_mat[i][j]=1;
                }
            }
        }
        //5. 开始广度搜索
        while (!q.empty())
        {
            pair<int,int> p=q.front();
            q.pop();
            //6. 遍历某个点的四个方向
            for (int i=0;i<4;i++)
            {
                int mx=p.first+dirX[i];
                int my=p.second+dirY[i];
           		//7. 只需要计算非零的元素的位置
                if (mx>=0 && mx<nr && my>=0 && my<nc && fg_mat[mx][my]==0)
                {
                	//8. 位置更新,由上一个的值 +1得到,走了一步
                    dst[mx][my]=dst[p.first][p.second]+1;
                    q.emplace(mx,my);
                    //9. 标记这个点已经走过了
                    fg_mat[mx][my]=1;
                }
            }
        }
        return dst;
    }
};

地图分析

传送门:
https://leetcode.cn/problems/as-far-from-land-as-possible/

地图上:0代表海洋,1代表陆地。找到海洋距离陆地最大的距离。 地图中只包含0和1两种。

这道题和上一道题基本类似:

我们寻找距离陆地最大的海洋的坐标位置,可以看作上一题:就是求距离0的最远的距离

上一题我们已经找到了每个点距离最近的0的距离,我们只需要找到这个值最大的点,即是距离最大的点,这道题的答案。
在这里插入图片描述

class Solution {
private:
    const int dirX[4]{0,0,-1,1};
    const int dirY[4]{-1,1,0,0};
public:
    int maxDistance(vector<vector<int>>& grid) {
        int nr=grid.size(),nc=grid[0].size();
        //1. 标记数组
        vector<vector<int>> fg_map(nr,vector<int>(nc));
        //2. 结果数组
        vector<vector<int>> dst(nr,vector<int>(nc));
        //3. 队列
        queue<pair<int,int>> q;
        //4. 忽略陆地:把陆地视作上一题的0,我们不考虑他们,把他们标记为1,但是要从他们开始进行广度优先搜索
        for (int i=0;i<nr;i++)
        {
            for (int j=0;j<nc;j++)
            {
                if (grid[i][j]==1)
                {
                    fg_map[i][j]=1;	//注意这个位置
                    q.emplace(i,j);
                }
            }
        }
        // Step: 如果队列为空或者包含全部的数组的元素,则表示全部是海洋或者陆地,返回-1
        // (1) q.size()==0  全都是0,即全部都是海洋
        // (2) q.size()==nr*nc 全部都是1,即全部都是陆地(刚才把陆地的值入队)
        if (q.size()==0 || q.size()==nr*nc)
        {
            //全都是海洋:0 陆地:1(队列等于总大小) 
            return -1;
        }
        //5. 队列不为空:遍历所有海洋
        while (!q.empty())
        {
            pair<int,int> p=q.front();
            q.pop();
            for (int i=0;i<4;i++)
            {
                int mx=p.first+dirX[i];
                int my=p.second+dirY[i];
                //6. 遍历每一方向,广度搜索海洋距离陆地的最大距离
                if (mx>=0 && mx<nr && my>=0 && my<nc && fg_map[mx][my]==0)
                {
                	//7. 更新结果数组: 由上一步 +1得到这个点的值(即是距离)
                    dst[mx][my]=dst[p.first][p.second]+1;
                    q.emplace(mx,my);
                    //8. 标记为已经走过
                    fg_map[mx][my]=1;
                }   
            }
        }
        //9. 找到dst结果的最大值,因为我们要找到海洋距离陆地的最大距离
        int maxnum=0;
        for (auto& x:dst)
        {
            for (auto& y:x)
            {
                maxnum=max(y,maxnum);
            }
        }
        return maxnum;
    }
};

腐烂的橘子

传送门:
https://leetcode.cn/problems/rotting-oranges/

题目:
值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
腐烂的距离每一分钟周围的四周都会腐烂,请问当所有的橘子都腐烂,一共需要多长时间,也可能会有不会腐烂的橘子,则返回-1.

我们需要:

  1. 标记数组:记录橘子的状态: 2腐烂,1正常, 0没有橘子
  2. 时间数组:记录时间状态: 0零分钟 1一分钟 … -1表示如果此位置有橘子,则为正常橘子,或者它无橘子,为空。

  1. 首先,标记数组将所有的腐烂的橘子标记为2,时间数组记录时间,如图一,这是第零分钟。
  2. 第一分钟红色为此时扩散的腐烂的橘子,表示数组更新为2(腐烂标记),时间数组更新为 1,表示第一分钟。
  3. 第二分钟蓝色为此时扩散的腐烂的橘子,表示数组更新为2,时间数组更新为 2,表示第二分钟。
  4. 第三分钟绿色为此时扩散的腐烂的橘子,表示数组更新为2,时间数组更新为 3,表示第三分钟。
  5. 第四分钟棕色为此时扩散的腐烂的橘子,表示数组更新为2,时间数组更新为 4,表示第四分钟。
  6. 此时:根据标记数组可知,所有的橘子都被腐烂了,即数组中无 1 出现,此时时间数组对应的 最大值即是最后的时间在这里插入图片描述
    没有腐烂的情况:
  • 标记数组中出现1正常的橘子,而且队列为空,无法继续。
  • 时间数组中出现 1是空或者是正常的橘子,需要对应标记数组来判断是那种情况。当然也可以直接在时间数组中再给空橘子单独设置一个值。
    在这里插入图片描述
class Solution {
private:
    const int dirX[4]{0,0,-1,1};
    const int dirY[4]{-1,1,0,0};
public:
    int orangesRotting(vector<vector<int>>& grid) {
        int nr=grid.size(),nc=grid[0].size();
        vector<vector<int>> fg(nr,vector<int>(nc));
        vector<vector<int>> time(nr,vector<int>(nc));
        queue<pair<int,int>> q;
        for (int i=0;i<nr;i++)
        {
            for (int j=0;j<nc;j++)
            {
                //腐烂橘子
                if (grid[i][j]==2)
                {
                    q.emplace(i,j);
                    fg[i][j]=2;     //腐烂橘子 表示为2
                    time[i][j]=0;   //时间数组 表示为0
                }
                if (grid[i][j]==1)
                {
                    fg[i][j]=1;     //正常橘子 表示为1
                    time[i][j]=-1;  //时间数组 表示为-1
                }
            }
        }
        while (!q.empty())
        {
            pair<int,int> p=q.front();
            q.pop();
            for (int i=0;i<4;i++)
            {
                int mx=p.first+dirX[i];
                int my=p.second+dirY[i];
                if (mx>=0 && mx<nr && my>=0 && my<nc && fg[mx][my]==1)
                {
                    fg[mx][my]=2;   //橘子变腐烂
                    time[mx][my]=time[p.first][p.second]+1;  //时间增加
                    q.emplace(mx,my);  //从下一个腐烂的橘子开始
                }
            }
        }
        int max_num=0;
        for (int i=0;i<nr;i++)
        {
            for (int j=0;j<nc;j++)
            {
                max_num=max(max_num,time[i][j]);
                //时间是-1,并且表示为1,则这个橘子未腐烂,返回-1
                if (time[i][j]==-1 && fg[i][j]==1)
                {
                    return -1;
                }
            }
        }
        return max_num;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb----Servlet技术

JavaEE简介 什么是JavaEE JavaEE&#xff08;Java Enterprise Edition&#xff09;&#xff0c;Java企业版&#xff0c;是一个用于企业 级web开发平台,它是一组Specification。最早由Sun公司定制并发 布&#xff0c;后由Oracle负责维护。在JavaEE平台规范了在开发企业级web 应…

【操作系统】死锁(详细)

文章目录一、死锁的概念二、死锁的产生因素三、死锁的必要条件1、互斥条件2、占有和等待条件&#xff08;部分分配条件&#xff09;3、不剥夺条件4、循环等待条件&#xff08;环路条件&#xff09;四、死锁防止1、破坏互斥条件2、破坏占有和等待条件3、破坏不剥夺条件4、破坏循…

Ceph文件系统

目录 一、环境准备 二、什么是文件系统 三、ceph块存储与文件系统区别 四、创建ceph文件系统 1、启动MDS服务 2、创建存储池 3、创建Ceph文件系统 4、客户端挂载 一、环境准备 Ceph集群搭建参照&#xff1a;Ceph集群部署_桂安俊kylinOS的博客-CSDN博客 以下Ceph存储实…

springcloud22:sentinal的使用

sentinal对比&#xff08;分布式系统的流量防卫&#xff09; 监控保护微服务 Hystrix 需要自己去手工搭建监控平台&#xff0c;没有一套web界面可以进行细粒度化的配置&#xff0c;流控&#xff0c;速率控制&#xff0c;服务熔断&#xff0c;服务降级… 整合机制&#xff1a;se…

外卖项目08---Linux

目录 一、 Linux简介 119 二、Linux安装 120 三、常用命令 122 3.1Linux命令初体验 3.1.1 command [-options] [parameter] 3.2Linux常用命令---文件目录操作命令-ls&-cd&-cat 124 3.2.1list 3.2.2 cd 3.2.3 cat 3.3 Linux常用命令---文件目录操作命令…

9.前端笔记-CSS-CSS三大特性

三大特性&#xff1a;层叠性、继承性、优先级 1、层叠性&#xff08;覆盖性&#xff09; 给相同的选择器设置相同的样式&#xff0c;此时一个样式会覆盖&#xff08;层叠&#xff09;其他冲突的样式。 层叠性原则&#xff1a; 同一选择器&#xff0c;样式冲突&#xff0c;遵…

OpenMV输出PWM,实现对舵机控制

OpenMV的定时器官方函数介绍&#xff1a;Timer类 – 控制内部定时器 目录 OpenMV的PWM资源介绍 为什么要用OpenMV输出PWM OpenMV的PWM资源分配 资源 注意 建议 PWM输出代码 代码讲解 Timer Timer.channel tim.channel与Timer.channel区别 Timer.channel解析 OpenM…

Iframe通信

跨域的种类 一般有两种形式的跨域问题&#xff1a; ①使用XmlHttpRequest(XHR)或者使用AJAX发送的POST或者GET请求。这种形式的跨域是&#xff1a;前端页面与后端进行的跨域请求。 ②父子页面之间进行的DOM操作&#xff08;父子窗口之间的document操作&#xff09;。这种形式…

使用XShell、XFTP 连接 win7 虚拟机(windows、Linux无法远程登录问题)

文章目录前言出错原因&#xff08;题外话&#xff09;那么我们为什么要使用 SSH 连接开始操作&#xff08;Windows7&#xff09;首先进行 SSH 测试获取所需的openSSH文件安装openSSH添加环境变量ssh测试发布ssh服务开始操作&#xff08;Linux&#xff0c;以Ubuntu为例&#xff…

Linux启动流程分析

一、Linux启动流程图 二、硬件启动流程 2.1、POST Linux开机加电后&#xff0c;系统开始开机自检&#xff0c;该过程主要对计算机各种硬件设备进行检测&#xff0c;如CPU、内存、主板、硬盘、CMOS芯片等。主要完成检测硬件能否满足运行的基本条件&#xff0c;叫做“硬件自检(P…

【网络编程】第一章 网络基础(协议+OSI+TCPIP+网络传输的流程+IP地址+MAC地址)

&#x1f3c6;个人主页&#xff1a;企鹅不叫的博客 ​ &#x1f308;专栏 C语言初阶和进阶C项目Leetcode刷题初阶数据结构与算法C初阶和进阶《深入理解计算机操作系统》《高质量C/C编程》Linux ⭐️ 博主码云gitee链接&#xff1a;代码仓库地址 ⚡若有帮助可以【关注点赞收藏】…

onnx-modifier使用

文章目录**0、作用和功能****1、准备****2、界面介绍****3、注意tips**onnx-modifier基于流行的模型可视化工具 Netron 和轻量级Web应用框架 flask 开发。希望它能给社区带来一些贡献0、作用和功能 经常作为不同框架模型转化的中间文件&#xff0c;拿到ONNX文件&#xff0c;想…

KMP算法【一句话概括什么是KMP】【手写 求next数组】【手写匹配过程】

这里写自定义目录标题1. 什么是KMP算法2. next数组的表示含义怎么算3. 匹配过程例题——KMP字符串1. 什么是KMP算法 KMP算法&#xff1a;给定abcabm字符串和abcabcabm字符串&#xff0c;求前面字符串在后面字符串出现的位置&#xff0c;我们从头开始依次遍历&#xff0c;当遍历…

Supervisor - 用户进程监控利器

Supervisor Supervisor 是一个客户端/服务器系统&#xff0c;允许用户在UNIX操作系统上监视、控制用户进程。从定义里面分析包含两层意思。 监控进程 - 监控进程状态 确定当前进程是否发生异常控制进程 - 针对进程异常情况 控制进程的行为 如重启当前进程 Supervisor 通过 F…

神经网络和深度学习-logistic回归

logistic回归 logistic回归常用于分类问题 &#xff0c;根据输入的x来估计属于不同类的概率为多少&#xff0c;满足分布&#xff0c;即所有类的概率总和为1 在torchvison包中提供了一些常用的数据集&#xff0c;供我们使用&#xff0c;例如&#xff1a;Mnist数据集 Cifar-10数…

力扣算法入门刷题2

12、删除排序链表中的重复元素 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2[ //链表结构 public class ListNode {* int val;* List…

【情感识别】BP神经网络语音情感识别【含Matlab源码 349期】

⛄一、BP神经网络语音情感识别简介 0 引言 随着科技的迅速发展, 人机交互显得尤为重要。语音是语言的载体, 是人与人之间交流的重要媒介。相较于其它交流方式而言, 语音交流更加直接、便捷。近年来, 随着人机交互研究的不断深入, 语音情感识别更成为了学术界研究的热点, 其涉及…

3年测试经验,投了300多份简历,没公司要我...

前言 软件测试行业3年多经验&#xff0c;学历大专自考本科&#xff0c;主要测试方向web&#xff0c;PC端&#xff0c;wap站&#xff0c;小程序公众号都测试过&#xff0c;app也测过一些&#xff0c;C端B端都有&#xff0c;除功能外&#xff0c;接口性能也有涉猎&#xff0c;但…

一条命令能实现前端本地代码和打包仓库的自动化提交?

背景&#xff1a; 先介绍我们原本的代码上线流程&#xff1a;首先发布仓和代码仓&#xff08;dev和master分支对应测试和生产环境&#xff09;独立&#xff0c;每次修复或新增功能&#xff0c;首先需要提交改动到代码仓&#xff08;fork&#xff09;&#xff0c;然后打包代码&…

TI Sitara系列 AM64x开发板——FreeRTOS、Baremetal案例开发案例

前 言 3 1 开发环境搭建 2 CCS工程编译与加载 3 FreeRTOS与Baremetal案例 评估板简介 创龙科技TL62x-EVM是一款基于TI Sitara系列AM62x单/双/四核ARM Cortex-A53 + 单核ARM Cortex-M4F异构多核处理器设计的高性能低功耗工业评估板,由核心板和评估底板组成。处理器ARM Cor…