- 公交路线
给你一个数组 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
解题思路
边界条件
如果原本起点和终点一致,则不用坐车
如果没有公交车,则不可达
如果起点和终点在同一条公交线路上,则坐一次公交就可以
先初始化并查集(但是需要以公交路线为图中的点)
然后再利用BFS进行搜索查找,知道起点和终点所在的公交路线有交集
class Solution {
public int numBusesToDestination(int[][] routes, int source, int target) {
if(source == target) return 0;
if(routes==null || routes.length==0 ) return -1;
List<Integer> before=new ArrayList<>();//记录出现source的公交车线路
List<Integer> after=new ArrayList<>();//记录出现target的公交车线路
int n=routes.length;
for(int i=0;i<n;i++){
Arrays.sort(routes[i]);//先将公交车的站点排序,便于之后查找
if(contains(routes[i],source)) before.add(i);
if(contains(routes[i],target)) after.add(i);
}
//如果before和after在一趟路线则直接返回1
for(int i:before){
if(after.contains(i)) return 1;
}
//记录和当前公交路线有交集的公交路线
HashMap<Integer,List<Integer>> routeMap=new HashMap<>();
boolean[] visited=new boolean[n];
//初始化routeMap
for(int i=0;i<n;i++){
visited[i]=false;
routeMap.put(i,new ArrayList<Integer>());
}
//更新routeMap
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(hasCommon(routes[i],routes[j])){
routeMap.get(i).add(j);
routeMap.get(j).add(i);
}
}
}
// 更新出发点使用线路信息 并 判断
boolean hasReached = false;//此时未到达
int count = 1;//先上车
while(!hasReached){
count++;//换乘下辆车
List<Integer> newbefore=new ArrayList<>();
//针对before中的每条公交线路
for(int beforeItem:before){
//遍历它可以到达的所有公交线路(有交集)
for(int routeItem:routeMap.get(beforeItem)){
//如果已经在上一个集合或者当前集合,则跳过
if(newbefore.contains(routeItem) || before.contains(routeItem)) continue;
//如果已经访问过,则继续
if(visited[routeItem]) continue;
//将该公交路线作为新的起点
newbefore.add(routeItem);
visited[routeItem]=true;
}
}
//证明不可继续前进
if(newbefore.size()==0) break;
//更新起点集合
before=newbefore;
//判断是否可达
for(int i:before){
if(after.contains(i)) hasReached=true;
}
}
return hasReached?count:-1;
}
//A和B都是有序数组
public boolean hasCommon(int[] A,int[] B){
int i=0,j=0;
while(i<A.length && j<B.length){
if(A[i]==B[j]) return true;
if(A[i]>B[j]) j++;
else i++;
}
return false;
}
public boolean contains(int[] route,int key){//二分查找判断公交路线是否含有某个站
int left=0;
int right=route.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(key == route[mid]) return true;
if(key > route[mid]) left=mid+1;
if(key < route[mid]) right=mid-1;
}
return false;
}
}
京公网安备 11010502036488号