LeetCode 2045. 到达目的地的第二短时间

本文介绍了一个利用广度优先搜索求解图中从起点到终点的第二短路径问题。在考虑交通信号灯的切换周期和等待时间的基础上,通过初始化最短路和次短路状态,进行迭代更新,最终找到目标路径。算法复杂度为O(n+m),适用于求解具有固定权重的边的图论问题。

一、题目

1、题目描述

  城市用一个 双向连通图 表示,图中有 n n n 个节点,从 1 1 1 n n n 编号(包含 1 1 1 n n n)。图中的边用一个二维整数数组 edges表示,其中每个 edges[i] = [ui, vi]表示一条节点 ui和节点 vi之间的双向连通边。每组节点对由 最多一条边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是 time分钟。
  每个节点都有一个交通信号灯,每 change分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都同时改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是 绿色 ,你 不能 在节点等待,必须离开。
  第二小的值 是 严格大于 最小值 的所有值中最小的值。
  例如,[2, 3, 4]中第二小的值是 3,而 [2, 2, 4]中第二小的值是 4
  给你 nedgestimechange,返回从节点 1 1 1 到节点 n n n 需要的 第二短时间 。
  注意:
    你可以 任意次 穿过任意顶点,包括 1 1 1 n n n
    你可以假设在 启程时 ,所有信号灯刚刚变成 绿色
  样例输入: n = 5, edges = [[1,2],[1,3],[1,4],[3,4],[4,5]], time = 3, change = 5
  样例输出: 13

2、基础框架

  • C++ 版本给出的基础框架代码如下:
class Solution {
public:
    int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
        
    }
};

3、原题链接

LeetCode 2045. 到达目的地的第二短时间

二、解题报告

1、思路分析

1)要点分析

   ( 1 ) (1) (1) 这个问题存在一个红灯、绿灯切换的问题。红灯是不能走的,需要等到下一个绿灯以后才能走。
   ( 2 ) (2) (2) 求最短路问题,大概率是广度优先搜索。
   ( 3 ) (3) (3) 求次短路问题,也是广度优先搜索,最短路记录的是最短路,次短路需要记录最短路和次短路。
   ( 4 ) (4) (4) 每条边权重是一样的。

2)算法详解

   ( 1 ) (1) (1) 对整个图建边(它是双向边)。
   ( 2 ) (2) (2) 初始化从1到所有点的最短路min[i] = inf,次短路submin[i] = inf
   ( 3 ) (3) (3) 初始化 1 到 1 的最短路为 min[1] = 0,并且塞入队列;
   ( 4 ) (4) (4) 循环迭代,从队列中取出一个结点u
     ( 4.1 ) (4.1) (4.1) 如果 submin[n] != inf,说明次短路找到了直接返回;
     ( 4.2 ) (4.2) (4.2) min[u]/change表示我的红绿灯改变了多少次,改变的次数只有两种情况:奇数 和 偶数,一开始绿灯,所以改变偶数次就还是绿灯,无需等待timewait = 0;而改变奇数次,需要等待的时间为timewait = change - min[u]%change
     ( 4.3 ) (4.3) (4.3) 对于每个和 u相邻的点v,从 1 -> ... -> u -> v的最短路为 min[u] + time + timewait,如果它比 min[v]小,则用它来更新min[v],并且同时更新次短路,把v塞入队列;
     ( 4.4 ) (4.4) (4.4) 如果 从 1 -> ... -> u -> v的最短路和 min[v]相等则跳过本次判断;
     ( 4.5 ) (4.5) (4.5) 如果 从 1 -> ... -> u -> v的最短路比次短路 submin[v]小,则更新次短路,把v塞入队列;
   ( 5 ) (5) (5) 然后,用次短路submin[u]执行同样的更新。

2、时间复杂度

   最坏时间复杂度 O ( n + m ) O(n + m) O(n+m)

3、代码详解

class Solution {
    #define maxn 10010
    #define inf -1

    vector <int> Edges[maxn];
    int min[maxn];
    int submin[maxn];

    void init(int n) {
        for(int i = 1; i <= n; ++i) {
            Edges[i].clear();
        }
        memset(min, inf, sizeof(min));
        memset(submin, inf, sizeof(submin));
    }

    bool smaller(int dist1, int dist2) {
        if(dist2 == inf) return true;
        if(dist1 == inf) return false;
        return dist1 < dist2;
    }

    void addEdge(int u, int v) {
        Edges[u].push_back(v);
        Edges[v].push_back(u);
    }
public:
    int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
        int i;
        queue <int> q;
        init(n);
        for(i = 0; i < edges.size(); ++i) {
            addEdge(edges[i][0], edges[i][1]);
        }

        min[1] = 0;
        q.push(1);

        /**********************上面的代码确保准确无误**********************/

        while(!q.empty()) {
            int u = q.front();
            q.pop();

            
            if(submin[n] != inf) {
                return submin[n];
            }
            vector<int> p = {min[u], submin[u]};

            for(int k = 0; k < p.size(); ++k) {
                int timered = (( p[k]/change ) & 1) ? ( change - p[k]%change ) : 0;
                int dist = p[k] + time + timered;
                if(p[k] == inf) {
                    continue;
                }
                // (u -> v)
                for(i = 0; i < Edges[u].size(); ++i) {
                    int v = Edges[u][i];
                    if( smaller(dist, min[v]) ) {
                        submin[v] = min[v];
                        min[v] = dist;
                        q.push(v);
                    }else if(dist == min[v]) {
                        continue;
                    }else if(smaller(dist, submin[v]) ) {
                        submin[v] = dist;
                        q.push(v);
                    }
                }
            }
        }
        return -1;
    }
};

三、本题小知识

  次短路比最短路多存了一维的状态。


四、加群须知

  相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」
  那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:

🌌《算法入门指引》🌌

  如果链接被屏蔽,或者有权限问题,可以私聊作者解决。

  大致题集一览:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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



在这里插入图片描述


  为了让这件事情变得有趣,以及「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括:线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为「 夜深人静写算法 」专家团 的一员。
  不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上,「 不会索取任何 」
  🔥联系作者,或者扫作者主页二维码加群,加入刷题行列吧🔥


🔥让天下没有难学的算法🔥

C语言免费动漫教程,和我一起打卡!
🌞《光天化日学C语言》🌞

让你养成九天持续刷题的习惯
🔥《九日集训》🔥

入门级C语言真题汇总
🧡《C语言入门100例》🧡

组团学习,抱团生长
🌌《算法零基础100讲》🌌

几张动图学会一种数据结构
🌳《画解数据结构》🌳

竞赛选手金典图文教程
💜《夜深人静写算法》💜
### 如何在 VSCode 中安装和配置 LeetCode 插件以及 Node.js 运行环境 #### 安装 LeetCode 插件 在 VSCode 的扩展市场中搜索 `leetcode`,找到官方提供的插件并点击 **Install** 按钮进行安装[^1]。如果已经安装过该插件,则无需重复操作。 #### 下载与安装 Node.js 由于 LeetCode 插件依赖于 Node.js 环境,因此需要下载并安装 Node.js。访问官方网站 https://nodejs.org/en/ 并选择适合当前系统的版本(推荐使用 LTS 版本)。按照向导完成安装流程后,需确认 Node.js 是否成功安装到系统环境中[^2]。 可以通过命令行运行以下代码来验证: ```bash node -v npm -v ``` 上述命令应返回对应的 Node.js 和 npm 的版本号。如果没有正常返回版本信息,则可能未正确配置环境变量。 #### 解决环境路径问题 即使完成了 Node.js 的安装,仍可能出现类似 “LeetCode extension needs Node.js installed in environment path” 或者 “command ‘leetcode.toggleLeetCodeCn’ not found” 的错误提示[^3]。这通常是因为 VSCode 未能识别全局的 Node.js 路径或者本地安装的 nvm 默认版本未被正确加载[^4]。 解决方法如下: 1. 手动指定 Node.js 可执行文件的位置 在 VSCode 设置界面中输入关键词 `leetcode`,定位至选项 **Node Path**,将其值设为实际的 Node.js 安装目录下的 `node.exe` 文件位置。例如:`C:\Program Files\nodejs\node.exe`。 2. 使用 NVM 用户管理工具调整默认版本 如果通过 nvm 工具切换了不同的 Node.js 版本,请确保设置了默认使用的版本号。可通过以下指令实现: ```bash nvm alias default <version> ``` 重新启动 VSCode 后测试功能键是否恢复正常工作状态。 --- #### 配置常用刷题语言 后一步是在 VSCode 设置面板中的 LeetCode 插件部分定义个人习惯采用的主要编程语言作为默认提交方式之一。这样可以减少频繁修改编码风格的时间成本。 --- ### 总结 综上所述,要在 VSCode 上顺利启用 LeetCode 插件及其关联服务,除了基本插件本身外还需额外准备支持性的后台框架——即 Node.js 应用程序引擎;同时针对特定场景下产生的兼容性障碍采取针对性措施加以修正即可达成目标[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值