【LeetCode】无权图的最短路精选7题——单源、多源

目录

无权图的单源最短路问题:

1. 迷宫中离入口最近的出口(中等)

2. 最小基因变化(中等)

3. 单词接龙(困难)

4. 为高尔夫比赛砍树(困难)

无权图的多源最短路问题:

1. 01矩阵(中等)

2. 地图中的最高点(中等)

3. 地图分析(中等)


无权图的单源最短路问题:

使用单源BFS可以求解无权图的单源最短路问题,这是由BFS总是按照距离由近到远来遍历图中每个顶点的性质决定的。

1. 迷宫中离入口最近的出口(中等)

class Solution {
public:
    int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
        int m = maze.size();
        int n = maze[0].size();
        vector<vector<bool>> visited(m, vector<bool>(n));
        int ans = 0;

        // 坐标上下左右的偏移量
        int dr[4] = { -1,1,0,0 };
        int dc[4] = { 0,0,-1,1 };

        queue<pair<int, int>> q;
        // 起始坐标入队并标记
        q.push({entrance[0], entrance[1]});
        visited[entrance[0]][entrance[1]] = true;
        while (!q.empty())
        {
            // 要向外拓展一层,步数++
            ans++;
            int count = q.size(); // 本层坐标点的个数
            for (int i = 0; i < count; i++)
            {
                // 队头出队
                auto [row, col] = q.front();
                q.pop();
                // 判断刚才出队的坐标上下左右是否满足条件,再判断是否到达出口,到达则直接返回,没到达则入队并标记
                for (int j = 0; j < 4; j++)
                {
                    int r = row + dr[j];
                    int c = col + dc[j];
                    if (r >= 0 && r < m && c >= 0 && c < n && maze[r][c] == '.' && !visited[r][c])
                    {
                        if (r == 0 || r == m - 1 || c == 0 || c == n - 1) // 到达出口
                            return ans;
                        q.push({r, c});
                        visited[r][c] = true;
                    }
                }
            }
        }
        return -1;
    }
};

2. 最小基因变化(中等)

将距离为1(变化了一个字符)的字符串连接起来构成一个无权图,求start到end的最短路。

class Solution {
public:
    int minMutation(string startGene, string endGene, vector<string>& bank) {
        unordered_set<string> hash(bank.begin(), bank.end()); // 哈希表记录基因库中的字符串
        unordered_set<string> visited; // 标记字符串是否被访问过
        string change = "ACGT";

        if (startGene == endGene)
            return 0;
        if (!hash.count(endGene))
            return -1;

        int ans = 0;
        queue<string> q;
        // 起始字符串入队并标记
        q.push(startGene);
        visited.insert(startGene);
        while (!q.empty())
        {
            // 要向外拓展一层,步数++
            ans++;
            int count = q.size(); // 本层字符串的个数
            for (int i = 0; i < count; i++)
            {
                // 队头出队
                string cur = q.front();
                q.pop();
                // 判断刚才出队的字符串只改变一个字符后是否满足条件,再判断是否到达end,到达则直接返回,没到达则入队并标记
                for (int i = 0; i < 8; i++)
                {
                    string tmp = cur;
                    for (int j = 0; j < 4; j++)
                    {
                        tmp[i] = change[j];
                        if (hash.count(tmp) && !visited.count(tmp))
                        {
                            if (tmp == endGene) // 到达end
                                return ans;
                            q.push(tmp);
                            visited.insert(tmp);
                        }
                    }
                }
            }
        }
        return -1;
    }
};

3. 单词接龙(困难)

和上一题“最小基因变化”类似,区别是上一题求步数,本题求最短路的顶点数。

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        unordered_set<string> hash(wordList.begin(), wordList.end()); // 哈希表记录字典中的单词
        unordered_set<string> visited; // 标记单词是否被访问过

        if (!hash.count(endWord))
            return 0;

        int ans = 1;
        queue<string> q;
        // 起始单词入队并标记
        q.push(beginWord);
        visited.insert(beginWord);
        while (!q.empty())
        {
            // 要向外拓展一层,顶点数++
            ans++;
            int count = q.size(); // 本层单词的个数
            for (int i = 0; i < count; i++)
            {
                // 队头出队
                string cur = q.front();
                q.pop();
                // 判断刚才出队的单词只改变一个字符后是否满足条件,再判断是否到达end,到达则直接返回,没到达则入队并标记
                for (int i = 0; i < cur.size(); i++)
                {
                    string tmp = cur;
                    for (char ch = 'a'; ch <= 'z'; ch++)
                    {
                        tmp[i] = ch;
                        if (hash.count(tmp) && !visited.count(tmp))
                        {
                            if (tmp == endWord) // 到达end
                                return ans;
                            q.push(tmp);
                            visited.insert(tmp);
                        }
                    }
                }
            }
        }
        return 0;
    }
};

4. 为高尔夫比赛砍树(困难)

1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7

给树按从小到大排序,求顺序相邻的树的最短路。

class Solution {
public:
    int cutOffTree(vector<vector<int>>& forest) {
        m = forest.size();
        n = forest[0].size();

        // 给树按从小到大排序,确定砍树的顺序
        vector<pair<int, int>> trees;
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (forest[i][j] > 1)
                {
                    trees.push_back({i, j});
                }
            }
        }
        sort(trees.begin(), trees.end(), [&](const pair<int, int>& p1, const pair<int, int>& p2)
        {
            return forest[p1.first][p1.second] < forest[p2.first][p2.second];
        });

        // 求顺序相邻的树的最短路
        int beginr = 0;
        int beginc = 0;
        int ans = 0;
        for (auto& [endr, endc] : trees)
        {
            int step = bfs(forest, beginr, beginc, endr, endc);
            if (step == -1)
                return -1;
            ans += step;
            beginr = endr;
            beginc = endc;
        }
        return ans;
    }

private:
    int bfs(vector<vector<int>>& forest, int beginr, int beginc, int endr, int endc)
    {
        if (beginr == endr && beginc == endc)
            return 0;
        
        vector<vector<bool>> visited(m, vector<bool>(n)); // 标记坐标是否被访问过
        int ans = 0;

        queue<pair<int, int>> q;
        // 起始坐标入队并标记
        q.push({beginr, beginc});
        visited[beginr][beginc] = true;
        while (!q.empty())
        {
            // 要向外拓展一层,步数++
            ans++;
            int count = q.size(); // 本层坐标点的个数
            for (int i = 0; i < count; i++)
            {
                // 队头出队
                auto [row, col] = q.front();
                q.pop();
                // 判断刚才出队的坐标上下左右是否满足条件,再判断是否到达end,到达则直接返回,没到达则入队并标记
                for (int j = 0; j < 4; j++)
                {
                    int r = row + dr[j];
                    int c = col + dc[j];
                    if (r >= 0 && r < m && c >= 0 && c < n && forest[r][c] && !visited[r][c])
                    {
                        if (r == endr && c == endc) // 到达end
                            return ans;
                        q.push({r, c});
                        visited[r][c] = true;
                    }
                }
            }
        }
        return -1;
    }

    // 坐标上下左右的偏移量
    int dr[4] = { -1,1,0,0 };
    int dc[4] = { 0,0,-1,1 };
    
    int m;
    int n;
};

无权图的多源最短路问题:

使用多源BFS可以求解无权图的多源最短路问题,将所有的源点当成一个“超级源点”,问题就变成了单源最短路问题。

1. 01矩阵(中等)

以所有的0为源点开始BFS。

距离数组dist最开始全部初始化为-1,表示没有被访问过,后续要修改成距离(步数)。所以,首先,我们不用创建visited数组标记坐标有没有被访问过;其次,不用创建step变量记录步数,并且不用计算本层坐标点的个数count,也就是说不用确定坐标点是在第几层。

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int m = mat.size();
        int n = mat[0].size();
        vector<vector<int>> dist(m, vector<int>(n, -1)); // 全部初始化为-1

        // 坐标上下左右的偏移量
        int dr[4] = { -1,1,0,0 };
        int dc[4] = { 0,0,-1,1 };
        
        queue<pair<int, int>> q;
        // 所有的源点入队并修改距离为0
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (mat[i][j] == 0)
                {
                    q.push({i, j});
                    dist[i][j] = 0;
                }
            }
        }
        while (!q.empty())
        {
            // 队头出队
            auto [row, col] = q.front();
            q.pop();
            // 判断刚才出队的坐标上下左右是否满足条件,满足条件则入队并修改距离
            for (int j = 0; j < 4; j++)
            {
                int r = row + dr[j];
                int c = col + dc[j];
                if (r >= 0 && r < m && c >= 0 && c < n && dist[r][c] == -1)
                {
                    q.push({r, c});
                    dist[r][c] = dist[row][col] + 1;
                }
            }
        }
        return dist;
    }
};

2. 地图中的最高点(中等)

水域格子的值是确定的,为0,以所有的0为源点开始BFS,和上一题“01矩阵”一模一样。

class Solution {
public:
    vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {
        int m = isWater.size();
        int n = isWater[0].size();
        vector<vector<int>> dist(m, vector<int>(n, -1)); // 全部初始化为-1

        // 坐标上下左右的偏移量
        int dr[4] = { -1,1,0,0 };
        int dc[4] = { 0,0,-1,1 };
        
        queue<pair<int, int>> q;
        // 所有的源点入队并修改距离为0
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (isWater[i][j] == 1)
                {
                    q.push({i, j});
                    dist[i][j] = 0;
                }
            }
        }
        while (!q.empty())
        {
            // 队头出队
            auto [row, col] = q.front();
            q.pop();
            // 判断刚才出队的坐标上下左右是否满足条件,满足条件则入队并修改距离
            for (int j = 0; j < 4; j++)
            {
                int r = row + dr[j];
                int c = col + dc[j];
                if (r >= 0 && r < m && c >= 0 && c < n && dist[r][c] == -1)
                {
                    q.push({r, c});
                    dist[r][c] = dist[row][col] + 1;
                }
            }
        }
        return dist;
    }
};

3. 地图分析(中等)

以所有的陆地单元格为源点开始BFS,陆地单元格对应在距离数组dist中的值为0,和“01矩阵”、“地图中的最高点”都是一样的题。

class Solution {
public:
    int maxDistance(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        vector<vector<int>> dist(m, vector<int>(n, -1)); // 全部初始化为-1
        int ans = -1;

        // 坐标上下左右的偏移量
        int dr[4] = { -1,1,0,0 };
        int dc[4] = { 0,0,-1,1 };
        
        queue<pair<int, int>> q;
        // 所有的源点入队并修改距离为0
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (grid[i][j] == 1)
                {
                    q.push({i, j});
                    dist[i][j] = 0;
                }
            }
        }
        while (!q.empty())
        {
            // 队头出队
            auto [row, col] = q.front();
            q.pop();
            // 判断刚才出队的坐标上下左右是否满足条件,满足条件则入队并修改距离
            for (int j = 0; j < 4; j++)
            {
                int r = row + dr[j];
                int c = col + dc[j];
                if (r >= 0 && r < m && c >= 0 && c < n && dist[r][c] == -1)
                {
                    q.push({r, c});
                    dist[r][c] = dist[row][col] + 1;
                    ans = max(ans, dist[r][c]);
                }
            }
        }
        return ans;
    }
};

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

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

相关文章

开源CMS Drupal本地快速部署并实现无公网ip环境远程访问

文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS&#xff0c;适用于各种不同的网站项目&#xff0c;从小型个人博客到大型企业级门户网站。它的学习…

蓝桥杯嵌入式第12届真题(完成) STM32G431

蓝桥杯嵌入式第12届真题(完成) STM32G431 题目 程序 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body**************************…

【业务功能篇135】多线程+countDownLatch执行大数据量定时任务

对于业务中存在一些功能需求&#xff0c;业务逻辑复杂且数据量大&#xff0c;过程处理也就比较繁琐&#xff0c;如果直接在单线程同步执行&#xff0c;效率就比较低了&#xff0c;所以我们需要利用多线程&#xff0c;开启多个线程去把任务分线程异步执行&#xff0c;这些效率就…

【java】小学生数学练习题目生成系统

本文章主要是CSDN-问答板块&#xff0c;有题主提出的问题&#xff0c;我这边将完整代码提供出来&#xff0c;仅供大家参考学习&#xff01; 一、效果截图 二、直接上代码 package com.example.dingtalk.question;import javax.script.ScriptEngine; import javax.script.Scrip…

点成分享|如何让地球更绿,它能给你答案

一、背景介绍 随着全球经济的飞速发展&#xff0c;环境问题也日益严重。现代社会面临着诸如全球变暖、气候异常、空气和水质污染等诸多环境问题。其中&#xff0c;温室气体的排放是导致全球变暖的主要原因之一。温室气体的排放量上升加剧气候异常&#xff0c;影响人类生存和自…

NFC三大工作模式及其在物联网应用实例

NFC支持三种通信模式&#xff1a;读写模式、点对点模式和卡模拟模式。在此三种模式下&#xff0c;都仅需简单点击便可启动传输。 在读写模式下&#xff0c;系统执行非接触式读写功能。该系统的NFC芯片与内置NFC的设备-诸如非接触式智能卡、NFC标签或具有NFC功能的智能手机&…

瑞盟MS5188N——16bit、8 通道、500kSPS、 SAR 型 ADC

产品简述 MS5188N 是 8 通道、 16bit 、电荷再分配逐次逼近型模数 转换器&#xff0c;采用单电源供电。 MS5188N 拥有多通道、低功耗数据采集系统所需的所有 组成部分&#xff0c;包括&#xff1a;无失码的真 16 位 SAR ADC &#xff1b;用于将输入配 置为单端输入…

unity学习(31)——跳转到角色选择界面(打勾?手滑挂错脚本)

There are 2 audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene. 是因为后来创建了一个camera&#xff0c;因为camera中自带一个组件Audio Listener。所以有两个camera就有两个audio listener导致报错。 一个简单的解决…

WebRTC最新版报错解决:city.wav:missing and no known rule to make it (二十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

读懂2024年数字孪生发展新趋势!十大权威白皮书放送!

2024年&#xff0c;数字孪生 该往哪些方向走&#xff1f; 新技术的不断涌现 又会带来怎样的行业变迁 …… 在开工之际&#xff0c;我们整理了 51WORLD主导、参编的 十大权威数字孪生白皮书、行业报告 以及产业优秀案例集 分享给想要提升自我的朋友们 读完这些 上面看似…

【数据结构】时间复杂度与空间复杂度

时间复杂度 算法的时间复杂度并不是指一个代码运行时间的快慢&#xff0c;因为在不同机器上运行的时间肯定不同&#xff0c;因此算法的时间复杂度指的是基本操作的执行次数&#xff0c;他是一个数学意义上的函数。这个函数并不是C语言中那种函数&#xff0c;而是一个数学函数&…

WebGL中开发科学数据可视化应用

WebGL在科学数据可视化领域有广泛的应用&#xff0c;可以用于呈现和解释复杂的科学数据。以下是在WebGL中开发科学数据可视化应用时的一些建议&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.选择合…

网络原理 - HTTP/HTTPS(4)

HTTP响应详解 认识"状态码"(status code) 状态码表示访问一个页面的结果.(是访问成功,还是失败,还是其它的一些情况...).(响应结果如何) 学习状态码 -> 为了调试问题. 写服务器时,按照状态码的含义正确使用. 200 OK 这是最常见的状态码,表示访问成功. 抓包抓…

Android加载富文本

直接用webview加载&#xff1a; package com.example.testcsdnproject;import androidx.appcompat.app.AppCompatActivity;import android.annotation.SuppressLint; import android.graphics.Color; import android.os.Bundle; import android.util.Log; import android.webk…

docker (十一)-进阶篇-docker-compos最佳实践部署zabbix

一 部署docker环境 关闭防火墙、selinux、开启docker&#xff0c;并设置开机自启动 注意点&#xff1a;docker部署的时候&#xff0c;bip要指定&#xff0c;不然会导致虚拟机ip和容器ip冲突&#xff0c;ssh连不上虚拟机 部署请参考 docker &#xff08;二&#xff09;-yum…

数据库管理-第153期 Oracle Vector DB AI-05(20240221)

数据库管理153期 2024-02-21 数据库管理-第153期 Oracle Vector DB & AI-05&#xff08;20240221&#xff09;1 Oracle Vector的其他特性示例1&#xff1a;示例2 2 简单使用Oracle Vector环境创建包含Vector数据类型的表插入向量数据 总结 数据库管理-第153期 Oracle Vecto…

计算机服务器中了devos勒索病毒怎么办?Devos勒索病毒解密数据恢复

网络技术的不断发展与更新&#xff0c;为企业的生产运营提供了有利保障&#xff0c;企业的生产运营离不开数据支撑&#xff0c;通过企业数据可以综合调整发展运营方向&#xff0c;但网络是一把双刃剑&#xff0c;近期&#xff0c;云天数据恢复中心接到许多企业的求助&#xff0…

2.20 Qt day1

一. 思维导图 二. 消化常用类的使用&#xff0c;以及常用成员函数对应的功能 按钮类QPushButton&#xff1a; mywidget.h&#xff1a; #ifndef MYWIDGET_H #define MYWIDGET_H#include <QWidget> #include<QPushButton>//按钮类 #include<QIcon>class MyW…

ts快速入门

文章目录 一、运行环境1、线上Playground2、VSCode 编辑器3、Code Runner 插件4、ts-node 二、声明1、变量声明2、常量声明3、类型推断 三、常用数据类型1、number2、string3、boolean4、数组5、对象 四、函数1、函数声明语法2、参数详解&#xff08;1&#xff09;特殊语法&…

C++学习Day08之类模板碰到继承的问题以及解决

目录 一、程序及输出1.1 指定父类T数据类型1.2 子类T指定父类T数据类型 二、分析与总结 一、程序及输出 1.1 指定父类T数据类型 必须要指定出父类中的T数据类型&#xff0c;才能给子类分配内存 正确使用 &#xff1a; #include<iostream> using namespace std;templa…