难度: Hard
Submission
运行时间: 56 ms
内存: 17.8 MB
class Solution: def busRapidTransit(self, target: int, inc: int, dec: int, jump: List[int], cost: List[int]) -> int: # (cost, station) pq = [(0, target)] visited_stations = set() ans = inf while pq: total_cost, station = heappop(pq) #print(total_cost, station, ans) if total_cost > ans: break if station == 0: ans = total_cost break if station in visited_stations: continue visited_stations.add(station) ans = min(ans, total_cost + station * inc) for j, c in zip(jump, cost): d, m = divmod(station, j) if d not in visited_stations: heappush(pq, (m * inc + total_cost + c, d)) if d + 1 not in visited_stations: heappush(pq, ((j - m) * dec + total_cost + c, d + 1)) return ans % (10 ** 9 + 7)
Explain
本题解采用了优先队列(最小堆)结合广度优先搜索的方法来寻找到达目标站点的最小花费。初始时,将目标站点放入优先队列,代表从目标站点逆向回到起点的代价为零(逆向思维)。然后逐渐将所有可能的站点及其花费压入优先队列。对于每个站点,计算直接步行到起点的花费,以及通过公交车跳跃后的新站点和对应花费。每次从优先队列中取出当前花费最小的站点,更新答案,并检查是否已到起点。如果达到起点站,记录总花费并结束搜索。否则,继续探索下一跳的可能站点。利用visited_stations集合避免重复处理同一站点,以优化搜索效率。
时间复杂度: O(n log n)
空间复杂度: O(n)
class Solution: def busRapidTransit(self, target: int, inc: int, dec: int, jump: List[int], cost: List[int]) -> int: # 初始化优先队列和访问集合 pq = [(0, target)] visited_stations = set() ans = inf # 处理每个状态 while pq: total_cost, station = heappop(pq) # 如果当前费用已经超过已知最小值,终止处理 if total_cost > ans: break # 到达起点站,更新最小费用 if station == 0: ans = total_cost break if station in visited_stations: continue visited_stations.add(station) # 直接步行到起点的费用 ans = min(ans, total_cost + station * inc) # 通过每种公交车处理新的状态 for j, c in zip(jump, cost): d, m = divmod(station, j) # 跳跃后站点不在访问集合中,则加入优先队列 if d not in visited_stations: heappush(pq, (m * inc + total_cost + c, d)) if d + 1 not in visited_stations: heappush(pq, ((j - m) * dec + total_cost + c, d + 1)) return ans % (10 ** 9 + 7)
Explore
逆向搜索的核心思想是将目标视为起点,从而逆向考虑到达实际起点的路径和费用。这种方法通过每次优先处理费用最小的站点(使用优先队列),确保了首先考虑的路径总是当前可能的最小费用路径。逆向处理允许算法在找到到达起点的可行路径时,已经确保这是花费最小的路径,因为所有后续考虑的路径都将具有更高的起始费用。这种策略有效地减少了搜索空间,并优化了性能。
在算法执行过程中,如果某个站点的处理费用`total_cost`已经超过了之前找到的最小费用`ans`,那么继续处理这个站点只会导致更高的总费用。因为从这个站点出发的任何进一步路径都会基于这个已经较高的`total_cost`,无法产生比`ans`更低的结果。基于最小堆的性质,队列中剩余的所有站点的开始处理费用也都不会低于当前的`total_cost`。因此,可以安全地忽略或停止处理费用已超标的站点,从而提高算法的效率。
优先队列(最小堆)在这类问题中的主要优势在于它能够保证每次从队列中取出的都是当前未处理站点中费用最小的一个。这种特性使得算法在每一步都优先考虑当前可能的最低成本路径,从而有效地找到全局最优解。此外,使用优先队列还可以高效地管理和更新待处理的站点集合,尤其是在涉及大量数据和频繁更新时,最小堆能够在对数时间内完成插入和删除最小元素操作,极大地优化了性能。