• 剑指Offer 815. 公交路线


    1. 题目

    给你一个数组 routes ,表示一系列公交线路,其中每个 routes[i] 表示一条公交线路,第 i 辆公交车将会在上面循环行驶。

    例如,路线 routes[0] = [1, 5, 7] 表示第 0 辆公交车会一直按序列 1 -> 5 -> 7 -> 1 -> 5 -> 7 -> 1 -> ... 这样的车站路线行驶。
    现在从 source 车站出发(初始时不在公交车上),要前往 target 车站。 期间仅可乘坐公交车。

    求出 最少乘坐的公交车数量 。如果不可能到达终点车站,返回 -1 。

    2. 示例

    示例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 <= 105
    routes[i] 中的所有值 互不相同
    sum(routes[i].length) <= 105
    0 <= routes[i][j] < 106
    0 <= source, target < 106

    3. 题解

    •  本题是一个无向图的搜索问题,但是题意很容易把我们弄混,可能一开始以为要将站台作为图上的点,其实应该将车作为点,如果两辆车的路线之间存在公共站点,那么就视作这两个点之间存在连线;
    • 因为需要绕弯,所以,同时用到多个映射用于保存车和站台,站台和车,车和车之间的关系。
    • 已经将问题转化为图的搜索问题了,那就很好做了,常规的做法就是将点与点关系存在映射之中,建立领接表,然后搜索映射。

    4. 实现

     1 public class NumBusesToDestination815 {
     2     // 建立邻接表,保存车到车之间是否存在直线的连线,也就是可以直接换成
     3     Map<Integer, Set<Integer>> bus2buses = new HashMap<>();
     4     // 保存车经过哪些站台, key是车, value是站台
     5     Map<Integer, Set<Integer>> bus2stations = new HashMap<>();
     6     // 保存站台有哪些车经过, key是站台, value是车
     7     Map<Integer, List<Integer>> station2buses = new HashMap<>();
     8     public int numBusesToDestination(int[][] routes, int source, int target) {
     9         if(source == target) return 0;
    10 
    11         int n = routes.length;
    12         int res = n + 1;
    13 
    14         // 初始化两个映射
    15         for(int i = 0; i < n; i++) {
    16             bus2buses.put(i, new HashSet<>());
    17             bus2stations.put(i, new HashSet<>());
    18         }
    19 
    20         // 初始化两个映射
    21         for(int i = 0; i < n; i++) { // 遍历所有车
    22             for(int r : routes[i]) { // 当前车经过的站台
    23                 if(!station2buses.containsKey(r)) { // station2buses未添加到hash表中
    24                     station2buses.put(r, new ArrayList<>()); // 添加站r并初始化
    25                 }
    26                 station2buses.get(r).add(i); // 将i车加入站r的列表
    27                 bus2stations.get(i).add(r); // 将r车加入站i的列表
    28             }
    29         }
    30 
    31         // 不存在target站
    32         if (!station2buses.containsKey(target)) return -1;
    33 
    34         // 填入车与车之间的直接关系
    35         for(int s : station2buses.keySet()) {
    36             for(int i = 0; i < station2buses.get(s).size(); i++) {
    37                 bus2buses.get(station2buses.get(s).get(i)).addAll(station2buses.get(s));
    38             }
    39         }
    40 
    41         // 遍历当前站台为出发点的所有车,作为dfs的出发车辆
    42         for(int cur : station2buses.get(source)) {
    43             // 存放经过出发站台的当前车辆,以及经过目的站台的所有车辆
    44             Set<Integer> start = new HashSet<>(), end = new HashSet<>();
    45             // 当前车辆加入起点集合
    46             start.add(cur);
    47             // 加入终点集合
    48             end.addAll(station2buses.get(target));
    49             // 如果当前车辆的路线中已经包含了目标站台,那么只乘一次车
    50             if(bus2stations.get(cur).contains(target)) return 1;
    51             // 广度优先搜索比较
    52             res = Math.min(res, bfs(start, end, 2, n));
    53         }
    54         return res == n + 1 ? -1 : res;
    55     }
    56 
    57     // 广度优先搜索,参数分别代表起点集合、终点集合、当前搜索的深度、最大深度
    58     private int bfs(Set<Integer> start, Set<Integer> end, int len, int max) {
    59         // 没有车辆或者
    60         if(start.size() == 0 || len > max) return max + 1;
    61         Set<Integer> next = new HashSet<>();
    62         // 枚举所有车辆
    63         for(int cur : start) {
    64             // 该车与其他车辆无连线
    65             if(!bus2buses.containsKey(cur)) continue;
    66             // 枚举与当前车辆有连线的所有车辆
    67             for(int b : bus2buses.get(cur)) {
    68                 // 如果当前车要经过目标车站,那么可以返回长度
    69                 if(end.contains(b)) return len;
    70                 // 不然需要将当前车辆放到下一个起点集合中再进行搜索
    71                 else next.add(b);
    72             }
    73         }
    74         return bfs(next, end, len + 1, max);
    75     }
    76 }

    5. 题解

      努力去爱周围的每一个人,付出,不一定有收获,但是不付出就一定没有收获! 给街头卖艺的人零钱,不和深夜还在摆摊的小贩讨价还价。愿我的博客对你有所帮助(*^▽^*)(*^▽^*)!

      如果客官喜欢小生的园子,记得关注小生哟,小生会持续更新(#^.^#)(#^.^#)。

    但行好事 莫问前程
  • 相关阅读:
    select_tag in rails about selected not change and onchange()
    debian7 请把标有“Debian GNU/Linux 7.1.0 _Wheezy_
    rails关于utf8问题-------------------utf8申明必须置顶
    ruby 删除文件
    svn conflict
    40亿个有序不同的数的文件中找一个缺失的数
    马云语录
    语音识别概率问题,一段在数学之美了看到的话
    两个有序数组的中位数
    磁盘文件排序-编程珠玑
  • 原文地址:https://www.cnblogs.com/haifwu/p/14947888.html
Copyright © 2020-2023  润新知