公交路线

本文探讨了在一系列公交路线中寻找从起始站到目标站的最少换乘次数问题,通过将每条公交路线视为图的一个节点,利用广度优先搜索算法在构建的图上寻找最短路径。

https://leetcode-cn.com/problems/bus-routes/
我们有一系列公交路线。每一条路线 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。


官方题解:https://leetcode-cn.com/problems/bus-routes/solution/gong-jiao-lu-xian-by-leetcode/

我们将每一条公交路线(而不是每一个车站)看成图中的一个点,如果两条公交路线有交集,那么它们在图中对应的点之间就有一条边.此外,起点站S和终点站T也分别是是图中的一个点,如果一条公交路线包含了S和T,那么也需要和S或T对应的点连成一条边.此时,在这个图上从S到T的最短路径长度即为答案,我们可以用广度优先搜索来找出最短路径.
在计算两条公交路线是否有交集时,可以用的方法有很多种.例如将公交路线放在集合中,检查这两个的集合的交集是否为空;或者将公交路线中的车站进行递增排序,并使用双指针的方法检查是否有相同车站

import java.awt.*;

class Solution {
    public static int numBusesToDestination(int[][] routes, int S, int T) {
        if (S == T){
            return 0;
        }
        int N = routes.length;

        List<List<Integer>> graph = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            Arrays.sort(routes[i]);
            graph.add(new ArrayList<>());
        }
        Set<Integer> seen = new HashSet<>();
        Set<Integer> targets = new HashSet<>();
        Queue<Point> queue = new ArrayDeque<>();

        //构建图表,如果两个公交路线共享至少一个公交车站,那么它们是连接的
        for (int i = 0; i < N; i++) {
            for (int j = i + 1; j < N; j++) {
                if (intersect(routes[i],routes[j])){
                    //共享,有连接
                    graph.get(i).add(j);
                    graph.get(j).add(i);
                }
            }
        }

        //初始化 seen,queue,targets
        //seen表示一个节点是否已经入队列
        //队列处理广度优先搜索
        //target是我们拥有的一组目标状态
        for (int i = 0; i < N; i++) {
            if (Arrays.binarySearch(routes[i],S) >= 0){
                seen.add(i);
                queue.offer(new Point(i,0));
            }
            if (Arrays.binarySearch(routes[i],T) >= 0){
                targets.add(i);
            }
        }
        while (!queue.isEmpty()){
            Point info = queue.poll();
            int node = info.x,depth = info.y;
            if (targets.contains(node)){
                return (depth + 1);
            }
            for (Integer nei : graph.get(node)){
                if (!seen.contains(nei)){
                    seen.add(nei);
                    queue.offer(new Point(nei,depth + 1));
                }
            }
        }
        return -1;
    }
    public static boolean intersect(int[] A,int[] B){
        int i = 0;
        int j = 0;
        while (i < A.length && j < B.length){
            if (A[i] == B[j]){
                return true;
            }
            if (A[i] < B[j]){
                i++;
            }else {
                j++;
            }
        }
        return false;
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值