AI刷题第61题 阿D的最佳飞行路线探索 (BFS算法)| 豆包MarsCode AI刷题

76 阅读4分钟

问题描述

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

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

求最小起飞次数。


测试样例

样例1:

输入:airports = [10, 12, 13, 12, 14]

输出:3

样例2:

输入:airports = [10, 11, 12, 13, 14]

输出:4

样例3:

输入:airports = [7, 7, 7, 8, 9, 7]

输出:1

解题思路:

一开始我的思路是,记录每个机场最先出现的distance,然后在顺序的上一个机场和同名机场中找取最小值,作为当前节点的distance。

int solution(std::vector<int> airports) {
    // Please write your code here
    unordered_map<int,int> m;
    vector<int> dis(airports.size(),-1);
    dis[0] = 0;
    m[airports[0]] = 0;
    for(int i=1;i<airports.size();++i){
        auto it = m.find(airports[i]);
        if(it!=m.end()){
            dis[i] = min(dis[i-1],m[airports[i]])+1;
        }
        else {
            dis[i] = dis[i-1]+1;
            m[airports[i]] = dis[i];
        }
        
    }
    return dis[airports.size()-1];
}

但是当我进行测试的时候,却无论如何也通不过,我就感觉很奇怪,最后发现题目中给的条件是,可以飞往当前机场的相邻机场或相同航空公司管理的机场。而我在上面的代码中实际上只考虑了前一个机场,这就是出现问题的关键。但是如果我采用单次的顺序遍历,那么注定后面的机场是未操作的。所以采取BFS的算法来解决这道题可能是一个比较好的选择。

广度优先搜索(BFS)是一种用于遍历图或树的算法,采用层次遍历的方式,从一个指定的起始节点开始,利用队列结构管理待访问的节点。BFS 每次从队列中取出一个节点,访问该节点并将所有未被访问的相邻节点添加到队列中,确保按照距离起始节点的层次顺序进行访问。通过这种方式,BFS 可以有效地找到无权图中两个节点之间的最短路径,因为它总是优先访问离起始节点最近的节点。同时,BFS 需要使用一个布尔数组或集合来标记已访问的节点,以防止重复访问和无限循环。由于其逐层遍历的特点,BFS 在解决社交网络分析、网络流量、状态空间搜索等问题中具有广泛应用。尽管 BFS 的空间复杂度通常为 O(V)(其中 V 是图中的节点数),但它在许多实际场景中仍然是一种高效且有效的搜索算法。

采用BFS算法,按照一层一层的顺序进行搜索,并且在访问了某一个节点之后,将该节点标记为已访问,从而进行减枝,这是因为我们是按照飞行次数进行BFS的,那么如果某个节点已经被访问了,那么之后访问该节点的飞行次数一定是大于先前的飞行次数的,那么就可以停止继续从该节点进行搜索,从而减少运算量。

另一方面,我们需要找到每个节点的可搜寻的子节点,在这道题中,子节点包括前一个机场、后一个机场以及所有的同名机场。在BFS的过程中,对于每个节点,找到其所有可访问的子节点,作为下一层搜寻的对象。

使用BFS算法的比较适配的数据结构是队列,在c++中可以是queue。如果是DFS,那么可以采用栈或者直接使用递归算法,也就是系统栈来进行搜索。

下面是我的具体的实现代码:

int solution(std::vector<int> airports) {
    int n = airports.size();
    if (n == 1) return 0; // 只有一个机场,起飞次数为0

    // 记录每个航空公司对应的机场索引
    std::unordered_map<int, std::vector<int>> airlineMap;
    for (int i = 0; i < n; ++i) {
        airlineMap[airports[i]].push_back(i);
    }

    // BFS 初始化
    std::queue<int> q;
    std::vector<bool> visited(n, false);
    q.push(0); // 从起始点出发
    visited[0] = true;

    int steps = 0;
    while (!q.empty()) {
        int size = q.size();
        for (int i = 0; i < size; ++i) {
            int current = q.front();
            q.pop();

            // 如果到达目的地
            if (current == n - 1) {
                return steps;
            }

            // 访问相邻的机场
            if (current - 1 >= 0 && !visited[current - 1]) {
                visited[current - 1] = true;
                q.push(current - 1);
            }
            if (current + 1 < n && !visited[current + 1]) {
                visited[current + 1] = true;
                q.push(current + 1);
            }

            // 访问相同航空公司的机场
            int airline = airports[current];
            for (int idx : airlineMap[airline]) {
                if (!visited[idx]) {
                    visited[idx] = true;
                    q.push(idx);
                }
            }
            // 在访问过后清空同一航空公司的机场,避免重复访问
            airlineMap[airline].clear();
        }
        steps++;
    }

    return -1; // 如果没有办法到达目的地(理论上不会发生)
}