问题描述
小C和他的领导小F计划一次飞行,但由于严格的航空管制,他们的飞机仅能按特定的路线飞行:飞机只能飞往当前机场的相邻机场或相同航空公司管理的机场。为了减少起飞次数,小C需要制定最优的飞行路线。机场由一个数组airports标识,其中:
- 数组每个元素代表一个独特的机场,元素的值代表不同的航空公司。
airports[0]为起点,airports[airports.length - 1]为终点。- 假设小C当前在机场
i,那么i - 1和i + 1(如果存在)代表邻近机场,飞机可以直接前往。 - 如果在机场
i,且存在airports[i] == airports[j],则机场i和机场j同属一家航空公司,可直接飞往。
求最小起飞次数。
问题解析
这是一个图搜索问题,可以通过 广度优先搜索 (BFS) 来解决,其中机场是节点,邻近的机场或同航空公司的机场是边。目标是找到从起点到终点的最短路径,也就是最少的起飞次数。
-
邻接关系:
- 当前机场可以飞往相邻的机场(
i-1和i+1,如果存在)。 - 当前机场可以直接飞往与其同属一家航空公司的其他机场。
- 当前机场可以飞往相邻的机场(
-
图的表示:
- 将机场的索引看作图中的节点,构造图中的边(邻接关系)。
- 每次飞行算作一个步数,从起点出发,寻找到终点的最短路径。
-
广度优先搜索:
- 使用 BFS 从
airports[0]出发,逐层搜索能够到达的机场。 - BFS 的特点是保证先到达的一定是最短路径。
- 使用 BFS 从
实现步骤:
- 使用一个队列存储当前可以到达的机场及其起飞次数。
- 用一个
visited数组记录访问过的机场,避免重复访问。 - 在 BFS 中,每次处理当前机场,尝试访问相邻的机场和同一家航空公司的机场。
- 如果到达终点,则输出当前步数。
代码实现
def solution(airports):
from collections import deque, defaultdict
n = len(airports)
if n <= 1:
return 0
# 构造航空公司索引,记录每个航空公司对应的机场索引
airline_map = defaultdict(list)
for i, company in enumerate(airports):
airline_map[company].append(i)
# BFS 队列,存储 (当前机场索引,当前起飞次数)
queue = deque([(0, 0)]) # 起点是 0,起飞次数是 0
visited = set() # 记录已经访问过的机场
visited.add(0)
while queue:
current, flights = queue.popleft()
# 如果到达终点,返回起飞次数
if current == n - 1:
return flights
# 获取邻接的机场
neighbors = []
if current - 1 >= 0:
neighbors.append(current - 1) # 左邻机场
if current + 1 < n:
neighbors.append(current + 1) # 右邻机场
# 同一家航空公司的机场
if airports[current] in airline_map:
neighbors.extend(airline_map[airports[current]])
# 避免重复访问,清空航空公司对应的索引(同一航空公司只需访问一次)
del airline_map[airports[current]]
# 遍历邻接机场
for neighbor in neighbors:
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, flights + 1))
return -1 # 如果没有路径(理论上不可能)
代码解析
-
构造航空公司索引: 使用
airline_map将每个航空公司对应的机场索引保存起来,这样可以快速找到同一家航空公司的机场。 -
BFS 队列:
- 每次从队列中取出当前机场和累计的起飞次数。
- 尝试访问邻近的机场和同航空公司的机场。
-
去重和优化:
- 使用
visited集合避免重复访问同一个机场。 - 一旦访问了某个航空公司的机场,清空对应的索引(
del airline_map[airports[current]]),避免再次浪费时间处理同一家航空公司。
- 使用
-
终止条件:
- 如果当前机场是终点(
current == n - 1),则返回起飞次数。
- 如果当前机场是终点(
时间复杂度
-
构造航空公司索引:O(n)
-
BFS 遍历:每个节点最多访问一次,邻接关系最多处理一次,时间复杂度为 O(n)。
-
总体复杂度:O(n)