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

原题地址戳这 ⬅️

城市用一个 双向连通 图表示,图中有 n 个节点,从 1 到 n 编号(包含 1 和 n)。图中的边用一个二维整数数组 edges 表示,其中每个 edges[i] = [ui, vi] 表示一条节点 ui 和节点 vi 之间的双向连通边。每组节点对由 最多一条 边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是 time 分钟。
每个节点都有一个交通信号灯,每 change 分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都 同时 改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是 绿色 ,你 不能 在节点等待,必须离开。

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

例如,[2, 3, 4] 中第二小的值是 3 ,而 [2, 2, 4] 中第二小的值是 4 。
给你 n、edges、time 和 change ,返回从节点 1 到节点 n 需要的 第二短时间 。

注意:

你可以 任意次 穿过任意顶点,包括 1 和 n 。
你可以假设在 启程时 ,所有信号灯刚刚变成 绿色
在这里插入图片描述

输入: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 分钟。      

在这里插入图片描述

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

解题思路

  • 尽管题目增加了红绿灯的设置,但求解最短时间其实等价于求解从节点1到节点n到最短路径
  • 图的最短路径求解,我们采用BFS,最后根据第二短路径求解第二短时间
    下图为时间求解表达式,摘自🔗
    在这里插入图片描述

踩过的坑

  • 在求最短路径的时候,我们可以直接等价于求解BFS时第一次访问到该顶点的路径;但是求次短路径时不能直接等价于第二次访问到该顶点:这是因为题目描述中提到"第二小的值 是 严格大于 最小值的所有值中最小的值",而第二次访问到该顶点的路径长度有可能等于最短路径。
    因此在求解的过程中,应该保存最短路径值,当找到大于最短路径的距离时才能跳出循环。
  • 剪枝问题:若再次访问到某个顶点时,他的路径距离等于最短路径,那么这个点不需要再加入列表中,避免多余的访问。
    当某个顶点已找到次短路径,在次访问到时也不需要加入列表
    这是由于本题中不关注具体路径,只关注路径长短
  • 将时间计算放在最后,避免在循环内增加多余运算
class Solution:
    def secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
    	# 初始化图	
        paths = defaultdict(list)
        for edge in edges:
        	# 注意是双向图
            paths[edge[0]].append(edge[1])
            paths[edge[1]].append(edge[0])

		# 初始化最短距离存储列表
        first = [float("inf") for _ in range(n + 1)]
        # 初始化次短距离存储列表
        second = [float("inf") for _ in range(n + 1)]
        # BFS
        q = deque()    
        q.append((1,0))
        # 循环终止条件为到节点n到次短距离已找到
        while second[n] == float("inf"):
            cur,step = q.popleft()
            step += 1
            for node in paths[cur]:
            	# 注意不能取等号;append在if内
                if step < first[node]:
                    first[node] = step
                    q.append((node,step))
                if first[node] < step < second[node]:
                    second[node] = step
                    q.append((node,step))
                
        # 由距离计算时间
        result = 0
        for _ in range(second[n]):
            if result % (2 * change) >= change:
                   result += 2 * change - result % (2 * change)
            result += time 
                    
        return result


在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值