阿D飞行 | 豆包MarsCode AI刷题

44 阅读4分钟

咱先see see 题目:

问题描述

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

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

一开始看到题目,嘿这不动态规划嘛,秒了。。。

意料之中的的WA,虽然题面给的测试样例过了。但卡在了如下样例: [7 16 3 10 17 21 7 16 12 10 5 17 13 25 17 18 22 21 6 11 20 13 20]

(画个Mermaid,效果很感人:))

stateDiagram-v2

1 --> 2
2 --> 1
2 --> 3
3 --> 2
3 --> 4
4 --> 3
4 --> 5
5 --> 4
5 --> 6
6 --> 5
6 --> 7
7 --> 6
7 --> 8
8 --> 7
8 --> 9
9 --> 8
9 --> 10
10 --> 9
10 --> 11
11 --> 10
11 --> 12
12 --> 11
12 --> 13
13 --> 12
13 --> 14
14 --> 13
14 --> 15
15 --> 14
15 --> 16
16 --> 15
16 --> 17
17 --> 16
17 --> 18
18 --> 17
18 --> 19
19 --> 18
19 --> 20
20 --> 19
20 --> 21
21 --> 20
21 --> 22
22 --> 21
22 --> 23
23 --> 22
1 --> 7
7 --> 1
2 --> 8
8 --> 2
4 --> 10
10 --> 4
5 --> 12
12 --> 5
5 --> 15
15 --> 5
12 --> 15
15 --> 12
13 --> 22
22 --> 13
21 --> 23
23 --> 21
6 --> 18
18 --> 6


图上看的很明显(大概),不能粗暴的dp,因为飞机可以往回飞,也可能可以dp,只是我太菜了:(

最终用粗暴的BFS

正文开始:)

解题思路

这个问题可以看作是一个图的最短路径问题。每个机场可以看作图中的一个节点,节点之间的边表示机场之间的飞行关系。具体来说:

  1. 节点:数组airports中的每个元素代表一个节点。

    • 相邻机场之间存在边(即ii-1i+1之间)。
    • 同一家航空公司的机场之间存在边(即airports[i] == airports[j])。

为了找到从起点到终点的最短路径,我们可以使用广度优先搜索(BFS)算法。BFS算法非常适合解决这类问题,因为它可以保证在找到目标节点时,路径是最短的。

数据结构选择

  • 队列:用于BFS算法,存储当前节点及其对应的起飞次数。
  • 集合:用于记录已经访问过的节点,避免重复访问。
  • 哈希表:用于存储同一家航空公司的机场索引,便于快速查找。

算法步骤

  1. 初始化

    • 创建一个队列queue,用于存储当前节点及其对应的起飞次数。
    • 创建一个集合visited,用于记录已经访问过的节点。
    • 创建一个哈希表map,用于存储同一家航空公司的机场索引。
  2. 构建图

    • 遍历airports数组,将同一家航空公司的机场索引存储到哈希表中。
  3. BFS搜索

    • 将起点(airports[0])及其起飞次数(0)入队。
    • 当队列不为空时,取出队首元素,检查其是否为终点。
    • 如果是终点,更新最小起飞次数。
    • 如果不是终点,将其相邻机场和同一家航空公司的机场加入队列,并标记为已访问。
  4. 返回结果

    • 如果找到路径,返回最小起飞次数;否则返回-1。

代码实现

public class Main {
    public static int solution(int[] airports) {
        // 创建队列和集合
        int res = Integer.MAX_VALUE;
        Queue<int[]> queue = new LinkedList<>();
        Set<Integer> visited = new HashSet<>();
        Map<Integer, ArrayList<Integer>> map = new HashMap<>();
        for (int i = 0; i < airports.length; i++) {
            if (map.containsKey(airports[i])) {
                map.get(airports[i]).add(i);
            } else {
                ArrayList<Integer> t = new ArrayList<>();
                t.add(i);
                map.put(airports[i], t);
            }
        }
        // 将起点机场和起飞次数入队
        queue.offer(new int[]{0, 0});
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int index = current[0];
            int steps = current[1];
            // 如果到达终点机场,返回起飞次数xd
            if (index == airports.length - 1) {
//                System.out.println(steps);
                res = Math.min(res, steps);
            }
            // 标记当前机场为已访问
            if (visited.contains(index)) {
                continue;
            } else {
                visited.add(index);
            }
            if (index >= airports.length) break;
            // 将相邻机场和同一家航空公司的机场加入队列
            if (index - 1 >= 0) queue.offer(new int[]{index - 1, steps + 1});
            if (map.containsKey(airports[index])) {
                for (int i : map.get(airports[index])) {
                    if (i == index) continue;
                    queue.offer(new int[]{i, steps + 1});
                }
            }
            if (index + 1 <= airports.length - 1) queue.offer(new int[]{index + 1, steps + 1});
        }
        // 如果没有找到路径,返回-1
        return res;
    }
}

总的来说还是一道比较简单题,虽然是中等题的标签

to be continue :))