阿D的最佳飞行路线探索
问题描述
小C和他的领导小F计划一次飞行,但由于严格的航空管制,他们的飞机仅能按特定的路线飞行:飞机只能飞往当前机场的相邻机场或相同航空公司管理的机场。为了减少起飞次数,小C需要制定最优的飞行路线。机场由一个数组airports标识,其中:
- 数组每个元素代表一个独特的机场,元素的值代表不同的航空公司。
airports[0]为起点,airports[airports.length - 1]为终点。- 假设小C当前在机场
i,那么i - 1和i + 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
解决思路
状态表示:
dp[i]表示从起点到达位置i所需的最小跳跃次数。
状态转移:
- 对于每个位置
i,计算到达该位置的最小跳跃次数。 - 假设
dp[i] = dp[i-1] + 1,即通过从前一个位置跳跃而来。 - 如果存在从
0到i-1的位置nearPort,且airports[nearPort] == airports[i](即nearPort和i的机场编号相同),那么可以从nearPort直接跳到i,这种跳跃不需要经过所有中间位置,跳跃次数为Math.min(dp[i-1], dp[nearPort]) + 1。
额外优化:
- 内层循环从
i - 1开始向前更新dp[k],通过dp[k] = Math.min(dp[i] + i - k, dp[k]),确保从位置i到k的路径是最短的。 - 这样处理可以减少后续的位置更新步骤。
代码
public class Main {
public static int solution(int[] airports) {
if(airports.length == 1){
return 0;
}
int[] dp = new int[airports.length];
dp[0] = 0;
dp[1] = 1;
for(int i = 2; i < airports.length; i++){
dp[i] = airports.length;
}
for(int i = 2; i < airports.length; i++){
int nearPort = 0;
while(nearPort < i && airports[nearPort] != airports[i]){
nearPort ++;
}
if(nearPort < i){
dp[i] = Math.min(dp[i-1], dp[nearPort]) + 1;
}else{
dp[i] = dp[i-1] + 1;
}
for(int k = i - 1; k >= 2; k--){
dp[k] = Math.min(dp[i]+i-k, dp[k]);
}
}
return dp[airports.length - 1];
}
public static void main(String[] args) {
// You can add more test cases here
int[] airports1 = {22, 21, 6, 13, 13, 14, 22, 13, 16, 6, 17, 15, 7, 10, 15, 24};
int[] airports2 = {10, 11, 12, 13, 14};
System.out.println(solution(airports1) == 7);
System.out.println(solution(airports2) == 4);
}
}