题目
我们有一系列公交路线。每一条路线 routes[i] 上都有一辆公交车在上面循环行驶。例如,有一条路线 routes[0] = [1, 5, 7],表示第一辆 (下标为0) 公交车会一直按照 1->5->7->1->5->7->1->… 的车站路线行驶。
假设我们从 S 车站开始(初始时不在公交车上),要去往 T 站。 期间仅可乘坐公交车,求出最少乘坐的公交车数量。返回 -1 表示不可能到达终点车站。
示例:
输入:
routes = [[1, 2, 7], [3, 6, 7]]
S = 1
T = 6
输出: 2
解释:
最优策略是先乘坐第一辆公交车到达车站 7, 然后换乘第二辆公交车到车站 6。
说明:
1 <= routes.length <= 500.
1 <= routes[i].length <= 500.
0 <= routes[i][j] < 10 ^ 6.
思路
这一题的主要思路就是广搜,那么我们可以考虑在每个公交站上标记经过它的线路,这样先遍历新增的点,再遍历这些点的线路(之前没走过的),不断循环即可。
这一次开始只跑了160ms,看到个76ms的算法和我的思路是一样的,然后发现unordered_map效率比map要高不少。同时也要注意判断冗余不一定都会加快速度,例如这一次若公交线路经过一些之前已经经过了的点,那么要判断这些点是否已经访问过的代价是挺大的(只能用map,因为公交站的站号很大),其实这些点就算冗余也没什么关系,因为一个点不可能有太多公交线路经过,用一个bool数组确保这些线路也不会重新访问,还是可以接受的。
class Solution {
public:
int numBusesToDestination(vector<vector<int>>& routes, int startPoint, int aimPoint){
if(startPoint == aimPoint){
return 0;
}
unordered_map<int ,vector<int> > pointMp; //map的查找比unordered_map慢。
queue<int> nextPoint ;
nextPoint.push(startPoint);
vector<bool> visitRoute(routes.size() , false);
int nowPointLength , nowDepth = 0;
for(int loop = 0 ;loop < routes.size() ; loop++ ){
for(int loop1 = 0 ; loop1 < routes[loop].size() ; loop1++){
int nowPoint = routes[loop][loop1];
pointMp[nowPoint ].push_back(loop);
}
}
while(!nextPoint.empty()){
vector<int> nextRoute;
nowPointLength = nextPoint.size();// 新一层的长度,因为nextPoint的大小会在后面改变,这里先记录
nowDepth++;
while(nowPointLength --){ // 遍历新的一层的公交站
int nowPoint = nextPoint.front();
nextPoint.pop();
for(auto nowRoute:pointMp[nowPoint]){ // 遍历公交站的线路
if(!visitRoute[ nowRoute ] ){
visitRoute[ nowRoute ] = true;
for(auto nowPoint:routes[nowRoute]){ // 将线路上没有访问过的点加入nextPoint
nextPoint.push(nowPoint); //用一个map检测点是否访问过,访问过就不放进nextPoint速度更慢
//应该是因为map的访问是logN复杂度,但一般情况下一个点只有少量线路
//重新遍历也没关系
if(nowPoint == aimPoint){
return nowDepth;
}
}
}
}
}
}
return -1;
}
};