公交路线 815
考虑到未来找实习和工作的需要,至少在心血来潮的时候刷刷LeetCode,顺便进行C++复健,顺便学学其他语言的语法。写下这道题也是在mark一个开始。这个难度的题大概以后也不会都写。。有(看)感(心)悟(情)或者足够变态的题目再写吧。
顺便感叹下DALL-E现在越来越厉害了。前几个博客的图都是生成的。
给你一个数组 routes
,表示一系列公交线路,其中每个 routes[i]
表示一条公交线路,第 i
辆公交车将会在上面循环行驶。
例如,路线 routes[0] = [1, 5, 7]
表示第 0 辆公交车会一直按序列 1 -> 5 -> 7 -> 1 -> 5 -> 7 -> 1 -> ...
这样的车站路线行驶。
现在从 source
车站出发(初始时不在公交车上),要前往 target
车站。 期间仅可乘坐公交车。
求出最少乘坐的公交车数量。如果不可能到达终点车站,返回 -1
。
示例 1:#
输入:routes = [[1,2,7],[3,6,7]], source = 1, target = 6
输出:2
解释:最优策略是先乘坐第一辆公交车到达车站 7,然后换乘第二辆公交车到车站 6。
示例 2:#
输入:routes = [[7,12],[4,5,15],[6],[15,19],[9,12,13]], source = 15, target = 12
输出:-1
提示:#
1 <= routes.length <= 500
1 <= routes[i].length <= 10^5
routes[i]
中的所有值 互不相同sum(routes[i].length) <= 10^5
0 <= routes[i][j] < 10^6
0 <= source, target < 10^6
分析与解答#
两年没做算法题目了。既然是复健,我将从直觉开始想。要求的是公交车数量,将两个车站之间的距离定义为公交车数量。循环行驶,说明可以看作是无向图。 这样一来,直接能想到的办法就是BFS。先不考虑优化,写出第一版。基本思路是从车站开始,遍历过这个站的车,更新到达站点的深度。根据BFS的特性,第一次到达站点的深度就是最小的。
基础复盘#
vector#
开始之前,我发现我需要快速过一下vector的用法。其他的STL用到再说。
unordered_map#
然后反向建图需要一个hash,这里用unordered_map。
用起来和Python还是很像的。实际复健的时候感觉C++也没那么难。可能是因为当时上课的时候不让用STL,一直没有简单的hash之类的用。。当时还自己写了好多板子:github
queue#
最后是queue,BFS的核心数据结构。就进进出出:
第一版代码#
于是,第一版代码:
过了一下测试,发现source target相等的时候不需要先上车再原地下车。。,不过总之这是一个特判。
测试结果是有一个case超时。分析一下时间,记m辆车,路线长n。反向建图的时间复杂度是O(mn),BFS的时间复杂度是O(mn)。所以按理说没问题才对?
仔细检查一下,发现实际上是因为BFS的时候,每次都要遍历一遍所有的车。构造极端情况:所有车首位相连成一条线。那么每个route交点上,都要遍历所有的车,再遍历所有站,时间复杂度就是O(m2n)。其实车看着不多,容易忽略这个复杂度。
第二版代码#
总之,每个bus只需要访问一次就可以了。在上面的基础上加入一个bus_visit,使用unordered_set,用法简单就不再讲了:
过。感觉其他细节也不算很重要,不继续优化了。简单说下优化思路:首先是更多特判,比如超出范围。然后深度不需要全部记下来,因为BFS是按层往下的,记录层数就够了。
顺便感叹一下今天收到的春江花月夜键盘(帽)。当初看到的时候就觉得特别变态!鉴定为盲打速成键盘。不知为何虽然平时基本也是盲打,但是用这个就是容易打错。难道其实平时有用余光?神奇。
题目 Link:公交路线 815