问题描述
小C和他的领导小F计划一次飞行,但由于严格的航空管制,他们的飞机仅能按特定的路线飞行:飞机只能飞往当前机场的相邻机场或相同航空公司管理的机场。为了减少起飞次数,小C需要制定最优的飞行路线。机场由一个数组 airports 标识,其中:
- 数组每个元素代表一个独特的机场,元素的值代表不同的航空公司。
airports[0]为起点,airports[airports.length - 1]为终点。- 如果小C当前在机场
i,那么i - 1和i + 1(如果存在)代表邻近机场,飞机可以直接前往。 - 如果在机场
i,且存在airports[i] == airports[j],则机场i和机场j同属一家航空公司,可直接飞往。
求最小起飞次数。结果需要对 109+7109+7 取模(虽然在这个问题中没有提到取模,但处理大数时可以考虑)。
思路分析
-
问题本质:
- 这是一个典型的图的最短路径问题,可以使用广度优先搜索(BFS)来解决。
- 每个机场可以看作图中的一个节点,相邻机场或同属一家航空公司的机场之间有边连接。
-
解决方案:
- 使用队列(
Queue)来进行广度优先搜索。 - 使用集合(
Set)来记录已经访问过的机场,避免重复访问。 - 初始状态为起点机场,起飞次数为0。
- 在每一步中,探索当前机场的相邻机场和同属一家航空公司的机场,并将这些机场及其起飞次数加入队列。
- 当到达终点机场时,返回起飞次数。
- 使用队列(
代码详解
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
public class Main {
public static int solution(int[] airports) {
Queue<int[]> queue = new LinkedList<>();
Set<Integer> visited = new HashSet<>();
// 初始状态:起点机场,起飞次数为0
queue.offer(new int[]{0, 0});
visited.add(0);
while (!queue.isEmpty()) {
int[] current = queue.poll();
int currentAirport = current[0];
int currentFlights = current[1];
// 如果到达终点,返回起飞次数
if (currentAirport == airports.length - 1) {
return currentFlights;
}
// 探索相邻机场
if (currentAirport + 1 < airports.length && !visited.contains(currentAirport + 1)) {
queue.offer(new int[]{currentAirport + 1, currentFlights + 1});
visited.add(currentAirport + 1);
}
if (currentAirport - 1 >= 0 && !visited.contains(currentAirport - 1)) {
queue.offer(new int[]{currentAirport - 1, currentFlights + 1});
visited.add(currentAirport - 1);
}
// 探索相同航空公司的机场
for (int i = 0; i < airports.length; i++) {
if (airports[i] == airports[currentAirport] && i != currentAirport && !visited.contains(i)) {
queue.offer(new int[]{i, currentFlights + 1});
visited.add(i);
}
}
}
// 如果没有找到路径,返回-1(理论上不会发生)
return -1;
}
public static void main(String[] args) {
int[] airports1 = {10, 12, 13, 12, 14};
int[] airports2 = {10, 11, 12, 13, 14};
System.out.println(solution(airports1)); // 输出 3
System.out.println(solution(airports1) == 3); // 输出 true
System.out.println(solution(airports2) == 4); // 输出 true
}
}
知识总结
-
广度优先搜索(BFS) :
- BFS 是一种图的遍历算法,适用于寻找最短路径问题。通过队列来存储待处理的节点,确保每一步都按层次访问节点。
- 使用集合记录已访问节点,避免重复处理,提高效率。
-
队列和集合:
- 在 Java 中,
LinkedList是一个常用的队列实现,可以高效地进行插入和删除操作。 HashSet用于存储不重复的元素,适合记录已访问的节点。
- 在 Java 中,
-
数组处理:
- 使用
for循环遍历数组中的每一个元素,处理每张卡牌。 - 通过
airports[i]获取当前机场的航空公司编号。
- 使用
-
边界条件:
- 考虑边界条件,确保数组索引不越界。例如,处理相邻机场时,需要检查
currentAirport + 1 < airports.length和currentAirport - 1 >= 0。
- 考虑边界条件,确保数组索引不越界。例如,处理相邻机场时,需要检查
个人理解与学习建议
-
问题简化:
- 这个问题的核心是找到从起点到终点的最短路径。通过广度优先搜索,可以有效地解决这个问题。
- 熟悉图的遍历算法,特别是BFS,有助于解决类似问题。
-
代码可读性:
- 在编写代码时,尽量使用有意义的变量名,如
currentAirport和currentFlights,这样可以使代码更易读。 - 添加注释,特别是对于复杂逻辑的部分,可以提高代码的可维护性。
- 在编写代码时,尽量使用有意义的变量名,如
-
性能考虑:
- BFS 算法的时间复杂度为 O(n)O(n),适用于中等规模的输入。
- 使用队列和集合可以有效地管理待处理节点和已访问节点,提高算法效率。
-
学习建议:
- 理解广度优先搜索:BFS 是一种重要的图遍历算法,适用于寻找最短路径问题。通过这个题目,可以加深对BFS的理解。
- 掌握队列和集合:熟练使用
LinkedList和HashSet,可以在很多问题中派上用场。 - 编写测试用例:在编写代码时,先思考测试用例,确保代码的正确性和鲁棒性。添加一些边界情况的测试用例,如只有一个机场、起点和终点同属一家航空公司等。
- 代码优化:在确保代码正确性的基础上,可以考虑优化代码的性能,例如使用并行流处理大数组。