- 公交路线
给你一个数组 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; } }