We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats forever. For example if routes[0] = [1, 5, 7], this means that the first bus (0-th indexed) travels in the sequence 1->5->7->1->5->7->1->... forever.

We start at bus stop S (initially not on a bus), and we want to go to bus stop T. Travelling by buses only, what is the least number of buses we must take to reach our destination? Return -1 if it is not possible.

Example:
Input:
routes = [[1, 2, 7], [3, 6, 7]]
S = 1
T = 6
Output: 2
Explanation:
The best strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6.

Note:

  • 1 <= routes.length <= 500.
  • 1 <= routes[i].length <= 500.
  • 0 <= routes[i][j] < 10 ^ 6.
 

这道题给了我们一堆公交线路表,然后给了起点和终点,问最少要换乘几辆公交可以从起点到达终点。这种原本只需要使用谷歌地图或者百度地图轻松实现的事,现在需要自己来实现。但这毕竟是简化版,真实情况一定要复杂得多。 这题容易进的一个误区就是把 routes 直接当作邻接链表来进行图的遍历,其实是不对的,因为 routes 数组的含义是,某个公交所能到达的站点,而不是某个站点所能到达的其他站点。这里出现了两种不同的结点,分别是站点和公交。而 routes 数组建立的是公交和其站点之间的关系,那么应该将反向关系数组也建立出来,即要知道每个站点有哪些公交可以到达。由于这里站点的标号不一定是连续的,所以可以使用 HashMap,建立每个站点和其属于的公交数组之间的映射。由于一个站点可以被多个公交使用,所以要用个数组来保存公交。既然这里求的是最少使用公交的数量,那么就类似迷宫遍历求最短路径的问题,BFS 应该是首先被考虑的解法。用队列 queue 来辅助,首先将起点S排入队列中,然后还需要一个 HashSet 来保存已经遍历过的公交(注意这里思考一下,为啥放的是公交而不是站点,因为统计的是最少需要坐的公交个数,这里一层就相当于一辆公交,最小的层数就是公交数),这些都是 BFS 的标配,应当已经很熟练了。在最开头先判断一下,若起点和终点相同,那么直接返回0,因为根本不用坐公交。否则开始 while 循环,先将结果 res 自增1,因为既然已经上了公交,那么公交个数至少为1,初始化的时候是0。这里使用 BFS 的层序遍历的写法,就是当前所有的结点都当作深度相同的一层,至于为何采用这种倒序遍历的 for 循环写法,是因为之后队列的大小可能变化,放在判断条件中可能会出错。在 for 循环中,先取出队首站点,然后要去 HashMap 中去遍历经过该站点的所有公交,若某个公交已经遍历过了,直接跳过,否则就加入 visited 中。然后去 routes 数组中取出该公交的所有站点,如果有终点,则直接返回结果 res,否则就将站点排入队列中继续遍历,参见代码如下:

解法一:

class Solution {
public:
int numBusesToDestination(vector<vector<int>>& routes, int S, int T) {
if (S == T) return ;
int res = ;
unordered_map<int, vector<int>> stop2bus;
queue<int> q{{S}};
unordered_set<int> visited;
for (int i = ; i < routes.size(); ++i) {
for (int j : routes[i]) {
stop2bus[j].push_back(i);
}
}
while (!q.empty()) {
++res;
for (int i = q.size(); i > ; --i) {
int t = q.front(); q.pop();
for (int bus : stop2bus[t]) {
if (visited.count(bus)) continue;
visited.insert(bus);
for (int stop : routes[bus]) {
if (stop == T) return res;
q.push(stop);
}
}
}
}
return -;
}
};

下面这种方法也是 BFS 解法,思路上跟上面的解法没有啥大的区别,就是数据结构的写法上略有不同。这里的队列 queue 放的是一个由站点和公交个数组成的 pair 对儿,这样就不用维护一个全局的最小公交数变量了。当然反向关系数组还是要建立出来的,即要知道每个站点有哪些公交可以到达。和上面稍有不同的是,使用了 HashSet 来保存经过某个站点的所有公交,但其实和用数组并没啥区别,因为这里没有查询需求,无法发挥 HashSet 的优势。由于对于每个站点,都保存了当达该站点所需的最少公交数,那么就不需要使用层序遍历的 BFS 的写法,直接用最一般的写法即可。还有一个不同之处在于,这里的 visited 保存的是遍历过的站点,而不再是公交了。在 while 循环中,首先将队首元素取出来,这里就取出来了当前站点 cur,和最少公交数 cnt,若当前站点就是终点,那就直接返回 cnt。否则遍历经过当前站点的所有公交,对每辆公交,再去遍历去所有站点,若站点已经被遍历过了,直接跳过,否则就加入 visited 中,并和 cnt+1 一起组成个 pair 对儿排入队列中继续遍历,参见代码如下:

解法二:

class Solution {
public:
int numBusesToDestination(vector<vector<int>>& routes, int S, int T) {
if (S == T) return ;
unordered_map<int, unordered_set<int>> stop2bus;
queue<pair<int, int>> q{{{S, }}};
unordered_set<int> visited;
for (int i = ; i < routes.size(); ++i) {
for (int j : routes[i]) {
stop2bus[j].insert(i);
}
}
while (!q.empty()) {
int cur = q.front().first, cnt = q.front().second; q.pop();
if (cur == T) return cnt;
for (int bus : stop2bus[cur]) {
for (int stop : routes[bus]) {
if (visited.count(stop)) continue;
visited.insert(stop);
q.push({stop, cnt + });
}
}
}
return -;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/815

参考资料:

https://leetcode.com/problems/bus-routes/

https://leetcode.com/problems/bus-routes/discuss/122712/Simple-Java-Solution-using-BFS

https://leetcode.com/problems/bus-routes/discuss/122771/C%2B%2BJavaPython-BFS-Solution

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Bus Routes 公交线路的更多相关文章

  1. [LeetCode] 815. Bus Routes 公交路线

    We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats forever. For e ...

  2. [Swift]LeetCode815. 公交路线 | Bus Routes

    We have a list of bus routes. Each routes[i]is a bus route that the i-th bus repeats forever. For ex ...

  3. 【leetcode】815. Bus Routes

    题目如下: We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats forever. ...

  4. 【BZOJ2004】[Hnoi2010]Bus 公交线路 状压+矩阵乘法

    [BZOJ2004][Hnoi2010]Bus 公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1 ...

  5. 【BZOJ2004】[HNOI2010]Bus 公交线路

    [BZOJ2004][HNOI2010]Bus 公交线路 题面 bzoj 洛谷 题解 $N$特别大$P,K$特别小,一看就是矩阵快速幂+状压 设$f[S]$表示公交车状态为$S$的方案数 这是什么意思 ...

  6. [HNOI 2010]Bus 公交线路

    Description 题库链接 有 \(N\) 个车站, \(K\) 条公交线路.第 \(1\) 到 \(K\) 站是这 \(K\) 线路的起点站.第 \(N-K+1\) 到 \(N\) 是终点站. ...

  7. LeetCode解题报告—— Bus Routes

    We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats forever. For e ...

  8. URAL 1137 Bus Routes(欧拉回路路径)

    1137. Bus Routes Time limit: 1.0 secondMemory limit: 64 MB Several bus routes were in the city of Fi ...

  9. 公交线路免费api接口代码

    描写叙述:本接口主要是依据城市名称 +  线路名称 模糊查找城市公交线路信息. 开源api接口:http://openapi.aibang.com/bus/lines?app_key=keyvalue ...

随机推荐

  1. 在NOARCHIVELOG和ARCHIVELOG模式之间选择

    本节介绍在选择以NOARCHIVELOG或ARCHIVELOG模式运行数据库时必须考虑的问题,并包含以下主题: 在NOARCHIVELOG模式下运行数据库 在ARCHIVELOG模式下运行数据库 是否 ...

  2. node命令行工具—cf-cli

    音乐分享: 钢心 - <龙王> 初喜<冠军>后喜<龙王> (PS:听一次钢心乐队的演出后采访才知道 “龙王”隐喻的是一起喝酒的老铁....) ——————————— ...

  3. IIS+nginx反向代理 负载均衡

    本文没有过多的讲述,只讲述重点地方.由这两个转自的文章进行中和 1.nginx+iis实现负载均衡(这篇文章主要是有第2篇文章的工具) 2.nginx+iis使用(这篇文章讲得很详细,配置文件直接复制 ...

  4. 关于COOKIE在本地可以正常写入发布后不能写入浏览器的问题

    看了一下cookie的属性设置如下: HTTP Cookie       设置了secure ,   该cookie只能在HTTPS通道下被写入浏览器. HTTPS Cookie     设置了sec ...

  5. 小程序 movable-view 在页面中的可移动图标

    项目中需要一个可拖动的小图标, 1.小程序组件movable-view 文档地址:https://developers.weixin.qq.com/miniprogram/dev/component/ ...

  6. unity iOS本地代码总结(一)

    1. 项目能直接运行了,但是代码的实际数据流动任然会有问题. 2. unity的代码能这么简单的被调用简直是奇迹一样,不需要大的改动就能够使用. 3. 目前需要注意的问题就是,unity的内容还太少, ...

  7. 高可用Redis(六):瑞士军刀之bitmap,HyperLoglog和GEO

    1.bitmap位图 1.1 bitmap位图的概念 首先来看一个例子,字符串big, 字母b的ASCII码为98,转换成二进制为 01100010 字母i的ASCII码为105,转换成二进制为 01 ...

  8. thymleaf th:text="|第${user.courseSort}课|" 对于不知道的真的是解渴了

    简单描述:最近再做一个课程管理,列表显示第几课,但是后台传递过来的只是数字0~9,意味着,我得自己拼了ヾ(◍°∇°◍)ノ゙  我最烦的就是这种拼,各种难调,果真和我想的一样,4.5遍了还没出来. 我的 ...

  9. sql 随笔更新

    SELECT DISTINCT(p.`id`), p.`id` , v.`full_name` , CONCAT(LEFT(v.mobile, 7), '****') , DATE_FORMAT(DA ...

  10. Windows安装redis并将redis设置成服务

    Redis 作为一种缓存工具,主要用于解决高并发的问题,在分布式系统中有着极其广泛的应用,Redis 本身是应用于 Linux/Unix 平台的(部署在服务器上边),官方并没有提供 Windows 平 ...