一、题目

有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 toi 抵达 pricei。

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1。

点击查看原题
难度级别: 中等

二、思路

1)动态规划

使用数组dp[i][j]代表经历i-1次中转,从srcj节点的最少花费,可以得到状态转移方程:
787. K 站中转内最便宜的航班-每日一题 - 图1
优化:由于只依赖i-1的状态,可以优化为两个一维数组

三、代码

1)动态规划

  1. class Solution {
  2. public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
  3. int[][] dp = new int[k+2][n];
  4. for (int i = 0; i <= k+1; ++i) {
  5. Arrays.fill(dp[i], Integer.MAX_VALUE);
  6. }
  7. dp[0][src] = 0;
  8. for (int i = 1; i <= k+1; i++) {
  9. for (int[] flight : flights) {
  10. if (dp[i-1][flight[0]] != Integer.MAX_VALUE) {
  11. dp[i][flight[1]] = Math.min(dp[i-1][flight[0]] + flight[2], dp[i][flight[1]]);
  12. }
  13. }
  14. }
  15. int ans = Integer.MAX_VALUE;
  16. for (int i = 0; i < k+2; i++) {
  17. ans = Math.min(ans, dp[i][dst]);
  18. }
  19. return ans == Integer.MAX_VALUE ? -1 : ans;
  20. }
  21. }

时间复杂度为O((flights.length + n)*k),空间复杂度为O(n*k)
优化代码如下:

  1. class Solution {
  2. public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
  3. int[] dp = new int[n];
  4. int ans = Integer.MAX_VALUE;
  5. Arrays.fill(dp, Integer.MAX_VALUE);
  6. dp[src] = 0;
  7. for (int i = 1; i <= k+1; i++) {
  8. int[] temp = new int[n];
  9. Arrays.fill(temp, Integer.MAX_VALUE);
  10. for (int[] flight : flights) {
  11. if (dp[flight[0]] != Integer.MAX_VALUE) {
  12. temp[flight[1]] = Math.min(dp[flight[0]] + flight[2], temp[flight[1]]);
  13. }
  14. }
  15. dp = temp;
  16. ans = Math.min(ans, dp[dst]);
  17. }
  18. return ans == Integer.MAX_VALUE ? -1 : ans;
  19. }
  20. }

时间复杂度为O((flights.length + n)*k),空间复杂度为O(n)