【Leetcode】2045. 到达目的地的第二短时间

本文介绍了一种利用广度优先搜索求解特定图上第二短时间路径的方法,并提供了一个具体的Python实现示例。

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

题目描述

城市用一个双向连通图表示,图中有 n 个节点,从 1 到 n 编号(包含 1 和 n)。图中的边用一个二维整数数组 edges 表示,其中每个 e d g e s [ i ] = [ u i , v i ] edges[i] = [u_i, v_i] edges[i]=[ui,vi] 表示一条节点 u i u_i ui 和节点 v i v_i vi 之间的双向连通边。每组节点对由 最多一条 边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是 time 分钟。

每个节点都有一个交通信号灯,每 change 分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都 同时 改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是 绿色 ,你 不能 在节点等待,必须离开。

第二小的值严格大于 最小值的所有值中最小的值。

  • 例如,[2, 3, 4] 中第二小的值是 3 ,而 [2, 2, 4] 中第二小的值是 4 。

给你 nedgestimechange ,返回从节点 1 到节点 n 需要的 第二短时间

注意:

  • 你可以 任意次 穿过任意顶点,包括 1 和 n 。
  • 你可以假设在 启程时 ,所有信号灯刚刚变成 绿色

示例1
到达目的地的第二短时间

输入:n = 5, edges = [[1,2],[1,3],[1,4],[3,4],[4,5]], time = 3, change = 5
输出:13
解释:
上面的左图展现了给出的城市交通图。
右图中的蓝色路径是最短时间路径。
花费的时间是:
- 从节点 1 开始,总花费时间=0
- 1 -> 43 分钟,总花费时间=3
- 4 -> 53 分钟,总花费时间=6
因此需要的最小时间是 6 分钟。

右图中的红色路径是第二短时间路径。
- 从节点 1 开始,总花费时间=0
- 1 -> 33 分钟,总花费时间=3
- 3 -> 43 分钟,总花费时间=6
- 在节点 4 等待 4 分钟,总花费时间=10
- 4 -> 53 分钟,总花费时间=13
因此第二短时间是 13 分钟。      

示例2
到达目的地的第二短时间

输入:n = 2, edges = [[1,2]], time = 3, change = 2
输出:11
解释:
最短时间路径是 1 -> 2 ,总花费时间 = 3 分钟
最短时间路径是 1 -> 2 -> 1 -> 2 ,总花费时间 = 11 分钟

提示

  • 2 < = n < = 1 0 4 2 <= n <= 10^4 2<=n<=104
  • n − 1 < = e d g e s . l e n g t h < = m i n ( 2 ∗ 1 0 4 , n ∗ ( n − 1 ) / 2 ) n - 1 <= edges.length <= min(2 * 10^4, n * (n - 1) / 2) n1<=edges.length<=min(2104,n(n1)/2)
  • e d g e s [ i ] . l e n g t h = = 2 edges[i].length == 2 edges[i].length==2
  • 1 < = u i , v i < = n 1 <= u_i, v_i <= n 1<=ui,vi<=n
  • u i ! = v i u_i != v_i ui!=vi
  • 不含重复边
  • 每个节点都可以从其他节点直接或者间接到达
  • 1 < = t i m e , c h a n g e < = 1 0 3 1 <= time, change <= 10^3 1<=time,change<=103

解题思路

根据题意可知,同一路径长度所需花费的时间是相同的,且路径越长,所需时间越久。因此,可以求得到达目的地的严格次短路径,就可以直接计算到达目的地的第二短时间。

求解权重相同的最短路径问题可以采用广度优先搜索,但是这里做一些修改。使用广度优先搜索求解最短路径时,经过的点与初始点的路径长度是所有未搜索过的路径中的最小值,因此每次广度优先搜索获得的经过点与初始点的路径长度是非递减的。可以记录下所有点与初始点的最短路径与严格次短路径,一旦求得目标点与严格次短路径,就可以直接计算到达目的地的第二短路径

对于路径长度与实践的计算,假设到达节点i的时间为 t i t_i ti,则到达节点 i + 1 i+1 i+1的时间为:
t i + 1 = t i + t w a i t + t i m e t_{i+1}=t_i+t_{wait}+time ti+1=ti+twait+time
其中, t w a i t t_{wait} twait的计算如下:
t w a i t = { 0  if  t i m o d    2 × c h a n g e ∈ [ 0 , c h a n g e ) 2 × c h a n g e − t i m o d    2 × c h a n g e  if  t i m o d    2 × c h a n g e ∈ [ c h a n g e , 2 × c h a n g e ) t_{wait}=\begin{cases} 0 & \text { if } {t_i\mod{2\times change}\in [0,change)}\\ 2\times change-t_i\mod{2\times change} & \text{ if }t_i \mod{2\times change}\in [change, 2 \times change) \end{cases} twait={02×changetimod2×change if timod2×change[0,change) if timod2×change[change,2×change)

代码展示

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  :SecondMinimum.py
# @Time      :2022/1/25 19:34
# @Author    :PangXZ
# Leetcode 2045:到达目的地的第二短时间
from collections import deque
from typing import List


class Solution:
    def secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
        graph = [[] for _ in range(n + 1)]  # 创建一个二维数组存储从每个节点出发的目的地
        for e in edges:
            x, y = e[0], e[1]
            graph[x].append(y)
            graph[y].append(x)

        # dist[i][0]表示从1到i的最短路径,dist[i][1]表示从1到i的严格次短路径
        dist = [[float('inf')] * 2 for _ in range(n + 1)]
        dist[1][0] = 0  # 表示 从1出发到它本身的最短路径为1
        q = deque([(1, 0)])  # 广度优先搜索队列,从1出发,步长为0
        while dist[n][1] == float('inf'):  # 表示从1到n的严格次短路径为无限大时,执行循环
            p = q.popleft()
            for y in graph[p[0]]:  # 遍历当前节点的所有可到达节点
                d = p[1] + 1  # 表示步长
                if d < dist[y][0]:  # 如果d小于当前到y的最短路径, 体现广度优先搜索
                    dist[y][0] = d  # 更新最短路径
                    q.append((y, d))
                elif dist[y][0] < d < dist[y][1]:  # 如果d大于当前到y的最短路径,小于到y的严格次短路径
                    dist[y][1] = d  # 更新严格次短路径
                    q.append((y, d))
        ans = 0
        for _ in range(int(dist[n][1])):  # 模拟从1开始到n的严格次短路径上的过程
            if ans % (change * 2) >= change:   # 如果当前超过达到信号灯变化的时刻, 则需要加上等待时间
                ans += change * 2 - ans % (change * 2)
            ans += time  # 加上通过时间
        return ans


if __name__ == "__main__":
    solution = Solution()
    print(solution.secondMinimum(n=5, edges=[[1, 2], [1, 3], [1, 4], [3, 4], [4, 5]], time=3, change=5))

内容来源:Leetcode 2045.到达目的地的第二短时间

### 如何在 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]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值