From bf641a247ab0fe9bb1696d4769d3b3bafe4d9752 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Tue, 17 Sep 2024 10:40:45 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.0815 --- solution/0800-0899/0815.Bus Routes/README.md | 370 ++++++++++------- .../0800-0899/0815.Bus Routes/README_EN.md | 373 ++++++++++-------- .../0800-0899/0815.Bus Routes/Solution.cpp | 68 ++-- .../0800-0899/0815.Bus Routes/Solution.cs | 56 ++- .../0800-0899/0815.Bus Routes/Solution.go | 73 ++-- .../0800-0899/0815.Bus Routes/Solution.java | 66 ++-- .../0800-0899/0815.Bus Routes/Solution.py | 48 +-- .../0800-0899/0815.Bus Routes/Solution.ts | 41 ++ 8 files changed, 601 insertions(+), 494 deletions(-) create mode 100644 solution/0800-0899/0815.Bus Routes/Solution.ts diff --git a/solution/0800-0899/0815.Bus Routes/README.md b/solution/0800-0899/0815.Bus Routes/README.md index cc8396d967a20..ead566d7884d6 100644 --- a/solution/0800-0899/0815.Bus Routes/README.md +++ b/solution/0800-0899/0815.Bus Routes/README.md @@ -35,7 +35,7 @@ tags:
 输入:routes = [[1,2,7],[3,6,7]], source = 1, target = 6
 输出:2
-解释:最优策略是先乘坐第一辆公交车到达车站 7 , 然后换乘第二辆公交车到车站 6 。 
+解释:最优策略是先乘坐第一辆公交车到达车站 7 , 然后换乘第二辆公交车到车站 6 。
 

示例 2:

@@ -64,17 +64,27 @@ tags: -### 方法一:建图 + BFS +### 方法一:BFS -对于本题,我们可以将公交线路看成图中的节点,对于任意两条公交线路,如果它们有公共的公交站点,那么这两个公交线路之间就有一条边。 +我们首先判断 $\textit{source}$ 和 $\textit{target}$ 是否相同,如果相同则直接返回 $0$。 -我们用 $s[i]$ 表示公交线路 $i$ 上的所有公交站点,用哈希表 $d$ 存储每个公交站对应的所有公交线路。 +然后我们使用一个哈希表 $\textit{g}$ 来构建站点到公交线路的映射。对于每一条公交线路,我们遍历其经过的所有站点,将每个站点映射到该公交线路,即 $\textit{g}[\textit{stop}]$ 为经过站点 $\textit{stop}$ 的所有公交线路。 -接下来我们开始建图。遍历哈希表 $d$ 中每个公交站对应的公交线路,同个公交站的任意两条公交线路之间都有一条边,因此我们可以将这些公交线路看成图中的节点,将这些节点之间的边加入图 $g$ 中。 +接着我们判断 $\textit{source}$ 和 $\textit{target}$ 是否在站点映射中,如果不在则返回 $-1$。 -接下来,我们可以通过 BFS 求出从 $source$ 到 $target$ 的最短路径,即为最少乘坐的公交车数量。 +我们使用一个队列 $\textit{q}$ 来进行广度优先搜索,队列中的每个元素为一个二元组 $(\textit{stop}, \textit{busCount})$,表示当前站点 $\textit{stop}$ 和到达当前站点所需的公交次数 $\textit{busCount}$。 -时间复杂度 $O(n\times m + n^2)$。其中 $n$, $m$ 分别表示公交线路的数量和公交站的数量。 +我们初始化一个集合 $\textit{visBus}$ 来记录已经访问过的公交线路,一个集合 $\textit{visStop}$ 来记录已经访问过的站点。然后我们将 $\textit{source}$ 加入到 $\textit{visStop}$ 中,并将 $(\textit{source}, 0)$ 加入到队列 $\textit{q}$ 中。 + +接下来我们开始广度优先搜索,当队列 $\textit{q}$ 不为空时,我们取出队列的第一个元素,即当前站点 $\textit{stop}$ 和到达当前站点所需的公交次数 $\textit{busCount}$。 + +如果当前站点 $\textit{stop}$ 是目标站点 $\textit{target}$,我们返回到达目标站点所需的公交次数 $\textit{busCount}$。 + +否则,我们遍历经过当前站点的所有公交线路,对于每一条公交线路,我们遍历该线路上的所有站点,如果某个站点 $\textit{nextStop}$ 没有被访问过,则将其加入到 $\textit{visStop}$ 中,并将 $(\textit{nextStop}, \textit{busCount} + 1)$ 加入到队列 $\textit{q}$ 中。 + +最后,如果无法到达目标站点,则返回 $-1$。 + +时间复杂度 $O(L)$,空间复杂度 $O(L)$,其中 $L$ 为所有公交线路上的站点总数。 @@ -87,38 +97,38 @@ class Solution: ) -> int: if source == target: return 0 - - # 一条公交线路有哪些公交站 - s = [set(r) for r in routes] - - # 一个公交站在哪些公交线路有 - d = defaultdict(list) - for i, r in enumerate(routes): - for v in r: - d[v].append(i) - + # 使用 defaultdict 构建站点到公交线路的映射 g = defaultdict(list) - for ids in d.values(): - m = len(ids) - for i in range(m): - for j in range(i + 1, m): - a, b = ids[i], ids[j] - g[a].append(b) - g[b].append(a) - q = deque(d[source]) - ans = 1 - vis = set(d[source]) - while q: - for _ in range(len(q)): - i = q.popleft() - if target in s[i]: - return ans - for j in g[i]: - if j not in vis: - vis.add(j) - q.append(j) - ans += 1 - return -1 + for i, route in enumerate(routes): + for stop in route: + g[stop].append(i) + + # 如果 source 或 target 不在站点映射中,返回 -1 + if source not in g or target not in g: + return -1 + + # 初始化队列和访问集合 + q = [(source, 0)] + vis_bus = set() + vis_stop = {source} + + # 开始广度优先搜索 + for stop, bus_count in q: + # 如果当前站点是目标站点,返回所需的公交次数 + if stop == target: + return bus_count + + # 遍历经过当前站点的所有公交线路 + for bus in g[stop]: + if bus not in vis_bus: + vis_bus.add(bus) + + # 遍历该线路上的所有站点 + for next_stop in routes[bus]: + if next_stop not in vis_stop: + vis_stop.add(next_stop) + q.append((next_stop, bus_count + 1)) + return -1 # 如果无法到达目标站点,返回 -1 ``` #### Java @@ -129,51 +139,51 @@ class Solution { if (source == target) { return 0; } - int n = routes.length; - Set[] s = new Set[n]; - List[] g = new List[n]; - Arrays.setAll(s, k -> new HashSet<>()); - Arrays.setAll(g, k -> new ArrayList<>()); - Map> d = new HashMap<>(); - for (int i = 0; i < n; ++i) { - for (int v : routes[i]) { - s[i].add(v); - d.computeIfAbsent(v, k -> new ArrayList<>()).add(i); - } - } - for (var ids : d.values()) { - int m = ids.size(); - for (int i = 0; i < m; ++i) { - for (int j = i + 1; j < m; ++j) { - int a = ids.get(i), b = ids.get(j); - g[a].add(b); - g[b].add(a); - } + + // 使用 HashMap 构建站点到公交线路的映射 + Map> g = new HashMap<>(); + for (int i = 0; i < routes.length; i++) { + for (int stop : routes[i]) { + g.computeIfAbsent(stop, k -> new ArrayList<>()).add(i); } } - Deque q = new ArrayDeque<>(); - Set vis = new HashSet<>(); - int ans = 1; - for (int v : d.get(source)) { - q.offer(v); - vis.add(v); + + // 如果 source 或 target 不在站点映射中,返回 -1 + if (!g.containsKey(source) || !g.containsKey(target)) { + return -1; } + + // 初始化队列和访问集合 + Deque q = new ArrayDeque<>(); + Set visBus = new HashSet<>(); + Set visStop = new HashSet<>(); + q.offer(new int[] {source, 0}); + visStop.add(source); + + // 开始广度优先搜索 while (!q.isEmpty()) { - for (int k = q.size(); k > 0; --k) { - int i = q.pollFirst(); - if (s[i].contains(target)) { - return ans; - } - for (int j : g[i]) { - if (!vis.contains(j)) { - vis.add(j); - q.offer(j); + int[] current = q.poll(); + int stop = current[0], busCount = current[1]; + + // 如果当前站点是目标站点,返回所需的公交次数 + if (stop == target) { + return busCount; + } + + // 遍历经过当前站点的所有公交线路 + for (int bus : g.get(stop)) { + if (visBus.add(bus)) { + // 遍历该线路上的所有站点 + for (int nextStop : routes[bus]) { + if (visStop.add(nextStop)) { + q.offer(new int[] {nextStop, busCount + 1}); + } } } } - ++ans; } - return -1; + + return -1; // 如果无法到达目标站点,返回 -1 } } ``` @@ -187,50 +197,53 @@ public: if (source == target) { return 0; } - int n = routes.size(); - vector> s(n); - vector> g(n); - unordered_map> d; - for (int i = 0; i < n; ++i) { - for (int v : routes[i]) { - s[i].insert(v); - d[v].push_back(i); - } - } - for (auto& [_, ids] : d) { - int m = ids.size(); - for (int i = 0; i < m; ++i) { - for (int j = i + 1; j < m; ++j) { - int a = ids[i], b = ids[j]; - g[a].push_back(b); - g[b].push_back(a); - } + + // 使用 unordered_map 构建站点到公交线路的映射 + unordered_map> g; + for (int i = 0; i < routes.size(); i++) { + for (int stop : routes[i]) { + g[stop].push_back(i); } } - queue q; - unordered_set vis; - int ans = 1; - for (int v : d[source]) { - q.push(v); - vis.insert(v); + + // 如果 source 或 target 不在站点映射中,返回 -1 + if (!g.contains(source) || !g.contains(target)) { + return -1; } + + // 初始化队列和访问集合 + queue> q; + unordered_set visBus; + unordered_set visStop; + q.push({source, 0}); + visStop.insert(source); + + // 开始广度优先搜索 while (!q.empty()) { - for (int k = q.size(); k; --k) { - int i = q.front(); - q.pop(); - if (s[i].count(target)) { - return ans; - } - for (int j : g[i]) { - if (!vis.count(j)) { - vis.insert(j); - q.push(j); + auto [stop, busCount] = q.front(); + q.pop(); + + // 如果当前站点是目标站点,返回所需的公交次数 + if (stop == target) { + return busCount; + } + + // 遍历经过当前站点的所有公交线路 + for (int bus : g[stop]) { + if (!visBus.contains(bus)) { + visBus.insert(bus); + // 遍历该线路上的所有站点 + for (int nextStop : routes[bus]) { + if (!visStop.contains(nextStop)) { + visStop.insert(nextStop); + q.push({nextStop, busCount + 1}); + } } } } - ++ans; } - return -1; + + return -1; // 如果无法到达目标站点,返回 -1 } }; ``` @@ -242,52 +255,109 @@ func numBusesToDestination(routes [][]int, source int, target int) int { if source == target { return 0 } - n := len(routes) - s := make([]map[int]bool, n) - g := make([][]int, n) - d := map[int][]int{} - for i, r := range routes { - for _, v := range r { - if s[i] == nil { - s[i] = make(map[int]bool) - } - s[i][v] = true - d[v] = append(d[v], i) - } - } - for _, ids := range d { - m := len(ids) - for i := 0; i < m; i++ { - for j := i + 1; j < m; j++ { - a, b := ids[i], ids[j] - g[a] = append(g[a], b) - g[b] = append(g[b], a) - } + + // 使用 map 构建站点到公交线路的映射 + g := make(map[int][]int) + for i, route := range routes { + for _, stop := range route { + g[stop] = append(g[stop], i) } } - q := d[source] - vis := map[int]bool{} - for _, v := range d[source] { - vis[v] = true + + // 如果 source 或 target 不在站点映射中,返回 -1 + if g[source] == nil || g[target] == nil { + return -1 } - ans := 1 - for len(q) > 0 { - for k := len(q); k > 0; k-- { - i := q[0] - q = q[1:] - if s[i][target] { - return ans - } - for _, j := range g[i] { - if !vis[j] { - vis[j] = true - q = append(q, j) + + // 初始化队列和访问集合 + q := list.New() + q.PushBack([2]int{source, 0}) + visBus := make(map[int]bool) + visStop := make(map[int]bool) + visStop[source] = true + + // 开始广度优先搜索 + for q.Len() > 0 { + front := q.Front() + q.Remove(front) + stop, busCount := front.Value.([2]int)[0], front.Value.([2]int)[1] + + // 如果当前站点是目标站点,返回所需的公交次数 + if stop == target { + return busCount + } + + // 遍历经过当前站点的所有公交线路 + for _, bus := range g[stop] { + if !visBus[bus] { + visBus[bus] = true + // 遍历该线路上的所有站点 + for _, nextStop := range routes[bus] { + if !visStop[nextStop] { + visStop[nextStop] = true + q.PushBack([2]int{nextStop, busCount + 1}) + } } } } - ans++ } - return -1 + + return -1 // 如果无法到达目标站点,返回 +} +``` + +#### TypeScript + +```ts +function numBusesToDestination(routes: number[][], source: number, target: number): number { + if (source === target) { + return 0; + } + + // 使用 Map 构建站点到公交线路的映射 + const g: Map = new Map(); + for (let i = 0; i < routes.length; i++) { + for (const stop of routes[i]) { + if (!g.has(stop)) { + g.set(stop, []); + } + g.get(stop)!.push(i); + } + } + + // 如果 source 或 target 不在站点映射中,返回 -1 + if (!g.has(source) || !g.has(target)) { + return -1; + } + + // 初始化队列和访问集合 + const q: [number, number][] = [[source, 0]]; + const visBus: Set = new Set(); + const visStop: Set = new Set([source]); + + // 开始广度优先搜索 + for (const [stop, busCount] of q) { + // 如果当前站点是目标站点,返回所需的公交次数 + if (stop === target) { + return busCount; + } + + // 遍历经过当前站点的所有公交线路 + for (const bus of g.get(stop)!) { + if (!visBus.has(bus)) { + visBus.add(bus); + // 遍历该线路上的所有站点 + for (const nextStop of routes[bus]) { + if (!visStop.has(nextStop)) { + visStop.add(nextStop); + q.push([nextStop, busCount + 1]); + } + } + } + } + } + + return -1; // 如果无法到达目标站点,返回 -1 } ``` diff --git a/solution/0800-0899/0815.Bus Routes/README_EN.md b/solution/0800-0899/0815.Bus Routes/README_EN.md index ebf250aa838af..88b81291ab647 100644 --- a/solution/0800-0899/0815.Bus Routes/README_EN.md +++ b/solution/0800-0899/0815.Bus Routes/README_EN.md @@ -64,7 +64,27 @@ tags: -### Solution 1 +### Solution 1: BFS + +First, we check if $\textit{source}$ and $\textit{target}$ are the same. If they are, we directly return $0$. + +Next, we use a hash table $\textit{g}$ to build a mapping from stops to bus routes. For each bus route, we traverse all the stops it passes through and map each stop to that bus route, i.e., $\textit{g}[\textit{stop}]$ represents all bus routes passing through stop $\textit{stop}$. + +Then, we check if $\textit{source}$ and $\textit{target}$ are in the stop mapping. If they are not, we return $-1$. + +We use a queue $\textit{q}$ to perform a breadth-first search (BFS). Each element in the queue is a tuple $(\textit{stop}, \textit{busCount})$, representing the current stop $\textit{stop}$ and the number of buses taken to reach the current stop $\textit{busCount}$. + +We initialize a set $\textit{visBus}$ to record the bus routes that have been visited and a set $\textit{visStop}$ to record the stops that have been visited. Then, we add $\textit{source}$ to $\textit{visStop}$ and $(\textit{source}, 0)$ to the queue $\textit{q}$. + +Next, we start the BFS. While the queue $\textit{q}$ is not empty, we take out the first element from the queue, which is the current stop $\textit{stop}$ and the number of buses taken to reach the current stop $\textit{busCount}$. + +If the current stop $\textit{stop}$ is the target stop $\textit{target}$, we return the number of buses taken to reach the target stop $\textit{busCount}$. + +Otherwise, we traverse all bus routes passing through the current stop. For each bus route, we traverse all stops on that route. If a stop $\textit{nextStop}$ has not been visited, we add it to $\textit{visStop}$ and add $(\textit{nextStop}, \textit{busCount} + 1)$ to the queue $\textit{q}$. + +Finally, if we cannot reach the target stop, we return $-1$. + +The time complexity is $O(L)$, and the space complexity is $O(L)$, where $L$ is the total number of stops on all bus routes. @@ -77,37 +97,25 @@ class Solution: ) -> int: if source == target: return 0 - - # 一条公交线路有哪些公交站 - s = [set(r) for r in routes] - - # 一个公交站在哪些公交线路有 - d = defaultdict(list) - for i, r in enumerate(routes): - for v in r: - d[v].append(i) - g = defaultdict(list) - for ids in d.values(): - m = len(ids) - for i in range(m): - for j in range(i + 1, m): - a, b = ids[i], ids[j] - g[a].append(b) - g[b].append(a) - q = deque(d[source]) - ans = 1 - vis = set(d[source]) - while q: - for _ in range(len(q)): - i = q.popleft() - if target in s[i]: - return ans - for j in g[i]: - if j not in vis: - vis.add(j) - q.append(j) - ans += 1 + for i, route in enumerate(routes): + for stop in route: + g[stop].append(i) + if source not in g or target not in g: + return -1 + q = [(source, 0)] + vis_bus = set() + vis_stop = {source} + for stop, bus_count in q: + if stop == target: + return bus_count + for bus in g[stop]: + if bus not in vis_bus: + vis_bus.add(bus) + for next_stop in routes[bus]: + if next_stop not in vis_stop: + vis_stop.add(next_stop) + q.append((next_stop, bus_count + 1)) return -1 ``` @@ -119,50 +127,42 @@ class Solution { if (source == target) { return 0; } - int n = routes.length; - Set[] s = new Set[n]; - List[] g = new List[n]; - Arrays.setAll(s, k -> new HashSet<>()); - Arrays.setAll(g, k -> new ArrayList<>()); - Map> d = new HashMap<>(); - for (int i = 0; i < n; ++i) { - for (int v : routes[i]) { - s[i].add(v); - d.computeIfAbsent(v, k -> new ArrayList<>()).add(i); - } - } - for (var ids : d.values()) { - int m = ids.size(); - for (int i = 0; i < m; ++i) { - for (int j = i + 1; j < m; ++j) { - int a = ids.get(i), b = ids.get(j); - g[a].add(b); - g[b].add(a); - } + + Map> g = new HashMap<>(); + for (int i = 0; i < routes.length; i++) { + for (int stop : routes[i]) { + g.computeIfAbsent(stop, k -> new ArrayList<>()).add(i); } } - Deque q = new ArrayDeque<>(); - Set vis = new HashSet<>(); - int ans = 1; - for (int v : d.get(source)) { - q.offer(v); - vis.add(v); + + if (!g.containsKey(source) || !g.containsKey(target)) { + return -1; } + + Deque q = new ArrayDeque<>(); + Set visBus = new HashSet<>(); + Set visStop = new HashSet<>(); + q.offer(new int[] {source, 0}); + visStop.add(source); + while (!q.isEmpty()) { - for (int k = q.size(); k > 0; --k) { - int i = q.pollFirst(); - if (s[i].contains(target)) { - return ans; - } - for (int j : g[i]) { - if (!vis.contains(j)) { - vis.add(j); - q.offer(j); + int[] current = q.poll(); + int stop = current[0], busCount = current[1]; + + if (stop == target) { + return busCount; + } + for (int bus : g.get(stop)) { + if (visBus.add(bus)) { + for (int nextStop : routes[bus]) { + if (visStop.add(nextStop)) { + q.offer(new int[] {nextStop, busCount + 1}); + } } } } - ++ans; } + return -1; } } @@ -177,49 +177,45 @@ public: if (source == target) { return 0; } - int n = routes.size(); - vector> s(n); - vector> g(n); - unordered_map> d; - for (int i = 0; i < n; ++i) { - for (int v : routes[i]) { - s[i].insert(v); - d[v].push_back(i); - } - } - for (auto& [_, ids] : d) { - int m = ids.size(); - for (int i = 0; i < m; ++i) { - for (int j = i + 1; j < m; ++j) { - int a = ids[i], b = ids[j]; - g[a].push_back(b); - g[b].push_back(a); - } + + unordered_map> g; + for (int i = 0; i < routes.size(); i++) { + for (int stop : routes[i]) { + g[stop].push_back(i); } } - queue q; - unordered_set vis; - int ans = 1; - for (int v : d[source]) { - q.push(v); - vis.insert(v); + + if (!g.contains(source) || !g.contains(target)) { + return -1; } + + queue> q; + unordered_set visBus; + unordered_set visStop; + q.push({source, 0}); + visStop.insert(source); + while (!q.empty()) { - for (int k = q.size(); k; --k) { - int i = q.front(); - q.pop(); - if (s[i].count(target)) { - return ans; - } - for (int j : g[i]) { - if (!vis.count(j)) { - vis.insert(j); - q.push(j); + auto [stop, busCount] = q.front(); + q.pop(); + + if (stop == target) { + return busCount; + } + + for (int bus : g[stop]) { + if (!visBus.contains(bus)) { + for (int nextStop : routes[bus]) { + if (!visStop.contains(nextStop)) { + visBus.insert(bus); + visStop.insert(nextStop); + q.push({nextStop, busCount + 1}); + } } } } - ++ans; } + return -1; } }; @@ -232,55 +228,96 @@ func numBusesToDestination(routes [][]int, source int, target int) int { if source == target { return 0 } - n := len(routes) - s := make([]map[int]bool, n) - g := make([][]int, n) - d := map[int][]int{} - for i, r := range routes { - for _, v := range r { - if s[i] == nil { - s[i] = make(map[int]bool) - } - s[i][v] = true - d[v] = append(d[v], i) - } - } - for _, ids := range d { - m := len(ids) - for i := 0; i < m; i++ { - for j := i + 1; j < m; j++ { - a, b := ids[i], ids[j] - g[a] = append(g[a], b) - g[b] = append(g[b], a) - } + + g := make(map[int][]int) + for i, route := range routes { + for _, stop := range route { + g[stop] = append(g[stop], i) } } - q := d[source] - vis := map[int]bool{} - for _, v := range d[source] { - vis[v] = true + + if g[source] == nil || g[target] == nil { + return -1 } - ans := 1 - for len(q) > 0 { - for k := len(q); k > 0; k-- { - i := q[0] - q = q[1:] - if s[i][target] { - return ans - } - for _, j := range g[i] { - if !vis[j] { - vis[j] = true - q = append(q, j) + + q := list.New() + q.PushBack([2]int{source, 0}) + visBus := make(map[int]bool) + visStop := make(map[int]bool) + visStop[source] = true + + for q.Len() > 0 { + front := q.Front() + q.Remove(front) + stop, busCount := front.Value.([2]int)[0], front.Value.([2]int)[1] + + if stop == target { + return busCount + } + + for _, bus := range g[stop] { + if !visBus[bus] { + visBus[bus] = true + for _, nextStop := range routes[bus] { + if !visStop[nextStop] { + visStop[nextStop] = true + q.PushBack([2]int{nextStop, busCount + 1}) + } } } } - ans++ } + return -1 } ``` +#### TypeScript + +```ts +function numBusesToDestination(routes: number[][], source: number, target: number): number { + if (source === target) { + return 0; + } + + const g: Map = new Map(); + for (let i = 0; i < routes.length; i++) { + for (const stop of routes[i]) { + if (!g.has(stop)) { + g.set(stop, []); + } + g.get(stop)!.push(i); + } + } + + if (!g.has(source) || !g.has(target)) { + return -1; + } + + const q: [number, number][] = [[source, 0]]; + const visBus: Set = new Set(); + const visStop: Set = new Set([source]); + + for (const [stop, busCount] of q) { + if (stop === target) { + return busCount; + } + for (const bus of g.get(stop)!) { + if (!visBus.has(bus)) { + visBus.add(bus); + for (const nextStop of routes[bus]) { + if (!visStop.has(nextStop)) { + visStop.add(nextStop); + q.push([nextStop, busCount + 1]); + } + } + } + } + } + return -1; +} +``` + #### C# ```cs @@ -290,45 +327,39 @@ public class Solution { return 0; } - Dictionary> stopToRoutes = new Dictionary>(); - List> routeToStops = new List>(); - + Dictionary> g = new Dictionary>(); for (int i = 0; i < routes.Length; i++) { - routeToStops.Add(new HashSet()); foreach (int stop in routes[i]) { - routeToStops[i].Add(stop); - if (!stopToRoutes.ContainsKey(stop)) { - stopToRoutes[stop] = new HashSet(); + if (!g.ContainsKey(stop)) { + g[stop] = new List(); } - stopToRoutes[stop].Add(i); + g[stop].Add(i); } } - Queue queue = new Queue(); - HashSet visited = new HashSet(); - int ans = 0; - - foreach (int routeId in stopToRoutes[source]) { - queue.Enqueue(routeId); - visited.Add(routeId); + if (!g.ContainsKey(source) || !g.ContainsKey(target)) { + return -1; } - while (queue.Count > 0) { - int count = queue.Count; - ans++; - - for (int i = 0; i < count; i++) { - int routeId = queue.Dequeue(); - - foreach (int stop in routeToStops[routeId]) { - if (stop == target) { - return ans; - } - - foreach (int nextRoute in stopToRoutes[stop]) { - if (!visited.Contains(nextRoute)) { - visited.Add(nextRoute); - queue.Enqueue(nextRoute); + Queue q = new Queue(); + HashSet visBus = new HashSet(); + HashSet visStop = new HashSet(); + q.Enqueue(new int[]{source, 0}); + visStop.Add(source); + + while (q.Count > 0) { + int[] current = q.Dequeue(); + int stop = current[0], busCount = current[1]; + if (stop == target) { + return busCount; + } + foreach (int bus in g[stop]) { + if (!visBus.Contains(bus)) { + foreach (int nextStop in routes[bus]) { + if (!visStop.Contains(nextStop)) { + visBus.Add(bus); + visStop.Add(nextStop); + q.Enqueue(new int[]{nextStop, busCount + 1}); } } } diff --git a/solution/0800-0899/0815.Bus Routes/Solution.cpp b/solution/0800-0899/0815.Bus Routes/Solution.cpp index 0d1355d77a7d7..87ff1a435d860 100644 --- a/solution/0800-0899/0815.Bus Routes/Solution.cpp +++ b/solution/0800-0899/0815.Bus Routes/Solution.cpp @@ -4,49 +4,45 @@ class Solution { if (source == target) { return 0; } - int n = routes.size(); - vector> s(n); - vector> g(n); - unordered_map> d; - for (int i = 0; i < n; ++i) { - for (int v : routes[i]) { - s[i].insert(v); - d[v].push_back(i); + + unordered_map> g; + for (int i = 0; i < routes.size(); i++) { + for (int stop : routes[i]) { + g[stop].push_back(i); } } - for (auto& [_, ids] : d) { - int m = ids.size(); - for (int i = 0; i < m; ++i) { - for (int j = i + 1; j < m; ++j) { - int a = ids[i], b = ids[j]; - g[a].push_back(b); - g[b].push_back(a); - } - } - } - queue q; - unordered_set vis; - int ans = 1; - for (int v : d[source]) { - q.push(v); - vis.insert(v); + + if (!g.contains(source) || !g.contains(target)) { + return -1; } + + queue> q; + unordered_set visBus; + unordered_set visStop; + q.push({source, 0}); + visStop.insert(source); + while (!q.empty()) { - for (int k = q.size(); k; --k) { - int i = q.front(); - q.pop(); - if (s[i].count(target)) { - return ans; - } - for (int j : g[i]) { - if (!vis.count(j)) { - vis.insert(j); - q.push(j); + auto [stop, busCount] = q.front(); + q.pop(); + + if (stop == target) { + return busCount; + } + + for (int bus : g[stop]) { + if (!visBus.contains(bus)) { + for (int nextStop : routes[bus]) { + if (!visStop.contains(nextStop)) { + visBus.insert(bus); + visStop.insert(nextStop); + q.push({nextStop, busCount + 1}); + } } } } - ++ans; } + return -1; } -}; \ No newline at end of file +}; diff --git a/solution/0800-0899/0815.Bus Routes/Solution.cs b/solution/0800-0899/0815.Bus Routes/Solution.cs index 0baab5a907de9..67b90242a10e8 100644 --- a/solution/0800-0899/0815.Bus Routes/Solution.cs +++ b/solution/0800-0899/0815.Bus Routes/Solution.cs @@ -4,45 +4,39 @@ public int NumBusesToDestination(int[][] routes, int source, int target) { return 0; } - Dictionary> stopToRoutes = new Dictionary>(); - List> routeToStops = new List>(); - + Dictionary> g = new Dictionary>(); for (int i = 0; i < routes.Length; i++) { - routeToStops.Add(new HashSet()); foreach (int stop in routes[i]) { - routeToStops[i].Add(stop); - if (!stopToRoutes.ContainsKey(stop)) { - stopToRoutes[stop] = new HashSet(); + if (!g.ContainsKey(stop)) { + g[stop] = new List(); } - stopToRoutes[stop].Add(i); + g[stop].Add(i); } } - Queue queue = new Queue(); - HashSet visited = new HashSet(); - int ans = 0; - - foreach (int routeId in stopToRoutes[source]) { - queue.Enqueue(routeId); - visited.Add(routeId); + if (!g.ContainsKey(source) || !g.ContainsKey(target)) { + return -1; } - while (queue.Count > 0) { - int count = queue.Count; - ans++; - - for (int i = 0; i < count; i++) { - int routeId = queue.Dequeue(); - - foreach (int stop in routeToStops[routeId]) { - if (stop == target) { - return ans; - } - - foreach (int nextRoute in stopToRoutes[stop]) { - if (!visited.Contains(nextRoute)) { - visited.Add(nextRoute); - queue.Enqueue(nextRoute); + Queue q = new Queue(); + HashSet visBus = new HashSet(); + HashSet visStop = new HashSet(); + q.Enqueue(new int[]{source, 0}); + visStop.Add(source); + + while (q.Count > 0) { + int[] current = q.Dequeue(); + int stop = current[0], busCount = current[1]; + if (stop == target) { + return busCount; + } + foreach (int bus in g[stop]) { + if (!visBus.Contains(bus)) { + foreach (int nextStop in routes[bus]) { + if (!visStop.Contains(nextStop)) { + visBus.Add(bus); + visStop.Add(nextStop); + q.Enqueue(new int[]{nextStop, busCount + 1}); } } } diff --git a/solution/0800-0899/0815.Bus Routes/Solution.go b/solution/0800-0899/0815.Bus Routes/Solution.go index 9f4ea10feb032..3c41190122280 100644 --- a/solution/0800-0899/0815.Bus Routes/Solution.go +++ b/solution/0800-0899/0815.Bus Routes/Solution.go @@ -2,50 +2,45 @@ func numBusesToDestination(routes [][]int, source int, target int) int { if source == target { return 0 } - n := len(routes) - s := make([]map[int]bool, n) - g := make([][]int, n) - d := map[int][]int{} - for i, r := range routes { - for _, v := range r { - if s[i] == nil { - s[i] = make(map[int]bool) - } - s[i][v] = true - d[v] = append(d[v], i) - } - } - for _, ids := range d { - m := len(ids) - for i := 0; i < m; i++ { - for j := i + 1; j < m; j++ { - a, b := ids[i], ids[j] - g[a] = append(g[a], b) - g[b] = append(g[b], a) - } + + g := make(map[int][]int) + for i, route := range routes { + for _, stop := range route { + g[stop] = append(g[stop], i) } } - q := d[source] - vis := map[int]bool{} - for _, v := range d[source] { - vis[v] = true + + if g[source] == nil || g[target] == nil { + return -1 } - ans := 1 - for len(q) > 0 { - for k := len(q); k > 0; k-- { - i := q[0] - q = q[1:] - if s[i][target] { - return ans - } - for _, j := range g[i] { - if !vis[j] { - vis[j] = true - q = append(q, j) + + q := list.New() + q.PushBack([2]int{source, 0}) + visBus := make(map[int]bool) + visStop := make(map[int]bool) + visStop[source] = true + + for q.Len() > 0 { + front := q.Front() + q.Remove(front) + stop, busCount := front.Value.([2]int)[0], front.Value.([2]int)[1] + + if stop == target { + return busCount + } + + for _, bus := range g[stop] { + if !visBus[bus] { + visBus[bus] = true + for _, nextStop := range routes[bus] { + if !visStop[nextStop] { + visStop[nextStop] = true + q.PushBack([2]int{nextStop, busCount + 1}) + } } } } - ans++ } + return -1 -} \ No newline at end of file +} diff --git a/solution/0800-0899/0815.Bus Routes/Solution.java b/solution/0800-0899/0815.Bus Routes/Solution.java index 6dedae230274e..3e59dbde501ad 100644 --- a/solution/0800-0899/0815.Bus Routes/Solution.java +++ b/solution/0800-0899/0815.Bus Routes/Solution.java @@ -3,50 +3,42 @@ public int numBusesToDestination(int[][] routes, int source, int target) { if (source == target) { return 0; } - int n = routes.length; - Set[] s = new Set[n]; - List[] g = new List[n]; - Arrays.setAll(s, k -> new HashSet<>()); - Arrays.setAll(g, k -> new ArrayList<>()); - Map> d = new HashMap<>(); - for (int i = 0; i < n; ++i) { - for (int v : routes[i]) { - s[i].add(v); - d.computeIfAbsent(v, k -> new ArrayList<>()).add(i); + + Map> g = new HashMap<>(); + for (int i = 0; i < routes.length; i++) { + for (int stop : routes[i]) { + g.computeIfAbsent(stop, k -> new ArrayList<>()).add(i); } } - for (var ids : d.values()) { - int m = ids.size(); - for (int i = 0; i < m; ++i) { - for (int j = i + 1; j < m; ++j) { - int a = ids.get(i), b = ids.get(j); - g[a].add(b); - g[b].add(a); - } - } - } - Deque q = new ArrayDeque<>(); - Set vis = new HashSet<>(); - int ans = 1; - for (int v : d.get(source)) { - q.offer(v); - vis.add(v); + + if (!g.containsKey(source) || !g.containsKey(target)) { + return -1; } + + Deque q = new ArrayDeque<>(); + Set visBus = new HashSet<>(); + Set visStop = new HashSet<>(); + q.offer(new int[] {source, 0}); + visStop.add(source); + while (!q.isEmpty()) { - for (int k = q.size(); k > 0; --k) { - int i = q.pollFirst(); - if (s[i].contains(target)) { - return ans; - } - for (int j : g[i]) { - if (!vis.contains(j)) { - vis.add(j); - q.offer(j); + int[] current = q.poll(); + int stop = current[0], busCount = current[1]; + + if (stop == target) { + return busCount; + } + for (int bus : g.get(stop)) { + if (visBus.add(bus)) { + for (int nextStop : routes[bus]) { + if (visStop.add(nextStop)) { + q.offer(new int[] {nextStop, busCount + 1}); + } } } } - ++ans; } + return -1; } -} \ No newline at end of file +} diff --git a/solution/0800-0899/0815.Bus Routes/Solution.py b/solution/0800-0899/0815.Bus Routes/Solution.py index 3dfb07db8d911..62d94ce5ac17f 100644 --- a/solution/0800-0899/0815.Bus Routes/Solution.py +++ b/solution/0800-0899/0815.Bus Routes/Solution.py @@ -4,35 +4,23 @@ def numBusesToDestination( ) -> int: if source == target: return 0 - - # 一条公交线路有哪些公交站 - s = [set(r) for r in routes] - - # 一个公交站在哪些公交线路有 - d = defaultdict(list) - for i, r in enumerate(routes): - for v in r: - d[v].append(i) - g = defaultdict(list) - for ids in d.values(): - m = len(ids) - for i in range(m): - for j in range(i + 1, m): - a, b = ids[i], ids[j] - g[a].append(b) - g[b].append(a) - q = deque(d[source]) - ans = 1 - vis = set(d[source]) - while q: - for _ in range(len(q)): - i = q.popleft() - if target in s[i]: - return ans - for j in g[i]: - if j not in vis: - vis.add(j) - q.append(j) - ans += 1 + for i, route in enumerate(routes): + for stop in route: + g[stop].append(i) + if source not in g or target not in g: + return -1 + q = [(source, 0)] + vis_bus = set() + vis_stop = {source} + for stop, bus_count in q: + if stop == target: + return bus_count + for bus in g[stop]: + if bus not in vis_bus: + vis_bus.add(bus) + for next_stop in routes[bus]: + if next_stop not in vis_stop: + vis_stop.add(next_stop) + q.append((next_stop, bus_count + 1)) return -1 diff --git a/solution/0800-0899/0815.Bus Routes/Solution.ts b/solution/0800-0899/0815.Bus Routes/Solution.ts new file mode 100644 index 0000000000000..3895be1e11362 --- /dev/null +++ b/solution/0800-0899/0815.Bus Routes/Solution.ts @@ -0,0 +1,41 @@ +function numBusesToDestination(routes: number[][], source: number, target: number): number { + if (source === target) { + return 0; + } + + const g: Map = new Map(); + for (let i = 0; i < routes.length; i++) { + for (const stop of routes[i]) { + if (!g.has(stop)) { + g.set(stop, []); + } + g.get(stop)!.push(i); + } + } + + if (!g.has(source) || !g.has(target)) { + return -1; + } + + const q: [number, number][] = [[source, 0]]; + const visBus: Set = new Set(); + const visStop: Set = new Set([source]); + + for (const [stop, busCount] of q) { + if (stop === target) { + return busCount; + } + for (const bus of g.get(stop)!) { + if (!visBus.has(bus)) { + visBus.add(bus); + for (const nextStop of routes[bus]) { + if (!visStop.has(nextStop)) { + visStop.add(nextStop); + q.push([nextStop, busCount + 1]); + } + } + } + } + } + return -1; +}