青训营X豆包MarsCode 技术训练营:AI刷题 问题61:阿D的最佳飞行路线探索| 豆包MarsCode AI 刷题

47 阅读3分钟

问题描述

小C和他的领导小F计划一次飞行,但由于严格的航空管制,他们的飞机仅能按特定的路线飞行:飞机只能飞往当前机场的相邻机场或相同航空公司管理的机场。为了减少起飞次数,小C需要制定最优的飞行路线。机场由一个数组airports标识,其中:

  • 数组每个元素代表一个独特的机场,元素的值代表不同的航空公司。
  • airports[0]为起点,airports[airports.length - 1]为终点。
  • 假设小C当前在机场i,那么i - 1i + 1(如果存在)代表邻近机场,飞机可以直接前往。
  • 如果在机场i,且存在airports[i] == airports[j],则机场i和机场j同属一家航空公司,可直接飞往。

求最小起飞次数。

问题解析

这是一个图搜索问题,可以通过 广度优先搜索 (BFS) 来解决,其中机场是节点,邻近的机场或同航空公司的机场是边。目标是找到从起点到终点的最短路径,也就是最少的起飞次数。

  1. 邻接关系

    • 当前机场可以飞往相邻的机场(i-1i+1,如果存在)。
    • 当前机场可以直接飞往与其同属一家航空公司的其他机场。
  2. 图的表示

    • 将机场的索引看作图中的节点,构造图中的边(邻接关系)。
    • 每次飞行算作一个步数,从起点出发,寻找到终点的最短路径。
  3. 广度优先搜索

    • 使用 BFS 从 airports[0] 出发,逐层搜索能够到达的机场。
    • BFS 的特点是保证先到达的一定是最短路径。

实现步骤:

  1. 使用一个队列存储当前可以到达的机场及其起飞次数。
  2. 用一个 visited 数组记录访问过的机场,避免重复访问。
  3. 在 BFS 中,每次处理当前机场,尝试访问相邻的机场和同一家航空公司的机场。
  4. 如果到达终点,则输出当前步数。

代码实现

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)