跳转至

656. 成本最小路径 🔒

题目描述

给你一个整数数组 coins(下标从 1 开始)长度为 n,以及一个整数 maxJump。你可以跳到数组 coins 的任意下标 i(满足 coins[i] != -1),访问下标 i 时需要支付 coins[i]。此外,如果你当前位于下标 i,你只能跳到下标 i + k(满足 i + k <= n),其中 k 是范围 [1, maxJump] 内的一个值。

初始时你位于下标 1coins[1] 不是 -1)。你的目标是找到一条到达下标 n 的成本最小路径。

返回一个整数数组,包含你访问的下标顺序,以便你以最小成本达到下标 n 。如果存在多条成本相同的路径,返回 字典序最小 的路径。如果无法达到下标 n ,返回一个空数组。

路径 p1 = [Pa1, Pa2, ..., Pax] 的长度为 x,路径 p2 = [Pb1, Pb2, ..., Pbx] 的长度为 y ,如果在两条路径的第一个不同的下标 j 处,Paj 小于 Pbj,则 p1 在字典序上小于 p2;如果不存在这样的 j,则较短的路径字典序较小。

 

示例 1:

输入:coins = [1,2,4,-1,2], maxJump = 2
输出:[1,3,5]

示例 2:

输入:coins = [1,2,4,-1,2], maxJump = 1
输出:[]

 

提示:

  • 1 <= coins.length <= 1000
  • -1 <= coins[i] <= 100
  • coins[1] != -1
  • 1 <= maxJump <= 100

解法

方法一:动态规划(逆向)

题目需要我们找到从下标 1 到下标 n 的最小花费路径,且字典序最小,我们可以使用动态规划求解。

我们定义 $f[i]$ 表示从下标 $i$ 到下标 $n-1$ 的最小花费。如果 $coins[n - 1] = -1$,则不存在从下标 $n-1$ 到下标 $n-1$ 的路径,直接返回空数组即可。否则 $f[n - 1] = coins[n - 1]$。

接下来,我们从下标 $n-2$ 开始,逆向遍历数组,对于下标 $i$,如果 $coins[i] = -1$,则 $f[i] = \infty$,否则 $f[i] = \min_{j = i + 1}^{min(n - 1, i + maxJump)} f[j] + coins[i]$。

然后我们判断 $f[0]$ 是否为 $\infty$,如果是,则不存在一条满足条件的路径,返回空数组即可。否则,我们的总花费为 $s = f[0]$,我们从下标 0 开始,向后遍历数组,如果 $f[i] = s$,则说明从下标 $i$ 到下标 $n-1$ 的花费为 $s$,我们将 $s$ 减去 $coins[i]$,并将下标 $i+1$ 加入到结果数组中,直到遍历到下标 $n-1$,返回结果数组即可。

时间复杂度 $O(n \times m)$,空间复杂度 $O(n)$。其中 $n$ 和 $m$ 分别为数组的长度和最大跳跃长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
    def cheapestJump(self, coins: List[int], maxJump: int) -> List[int]:
        if coins[-1] == -1:
            return []
        n = len(coins)
        f = [inf] * n
        f[-1] = coins[-1]
        for i in range(n - 2, -1, -1):
            if coins[i] != -1:
                for j in range(i + 1, min(n, i + maxJump + 1)):
                    if f[i] > f[j] + coins[i]:
                        f[i] = f[j] + coins[i]
        if f[0] == inf:
            return []
        ans = []
        s = f[0]
        for i in range(n):
            if f[i] == s:
                s -= coins[i]
                ans.append(i + 1)
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
    public List<Integer> cheapestJump(int[] coins, int maxJump) {
        int n = coins.length;
        List<Integer> ans = new ArrayList<>();
        if (coins[n - 1] == -1) {
            return ans;
        }
        int[] f = new int[n];
        final int inf = 1 << 30;
        Arrays.fill(f, inf);
        f[n - 1] = coins[n - 1];
        for (int i = n - 2; i >= 0; --i) {
            if (coins[i] != -1) {
                for (int j = i + 1; j < Math.min(n, i + maxJump + 1); ++j) {
                    if (f[i] > f[j] + coins[i]) {
                        f[i] = f[j] + coins[i];
                    }
                }
            }
        }
        if (f[0] == inf) {
            return ans;
        }
        for (int i = 0, s = f[0]; i < n; ++i) {
            if (f[i] == s) {
                s -= coins[i];
                ans.add(i + 1);
            }
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
    vector<int> cheapestJump(vector<int>& coins, int maxJump) {
        int n = coins.size();
        vector<int> ans;
        if (coins[n - 1] == -1) {
            return ans;
        }
        int f[n];
        const int inf = 1 << 30;
        f[n - 1] = coins[n - 1];
        for (int i = n - 2; ~i; --i) {
            f[i] = inf;
            if (coins[i] != -1) {
                for (int j = i + 1; j < min(n, i + maxJump + 1); ++j) {
                    f[i] = min(f[i], f[j] + coins[i]);
                }
            }
        }
        if (f[0] == inf) {
            return ans;
        }
        for (int i = 0, s = f[0]; i < n; ++i) {
            if (f[i] == s) {
                s -= coins[i];
                ans.push_back(i + 1);
            }
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func cheapestJump(coins []int, maxJump int) (ans []int) {
    n := len(coins)
    if coins[n-1] == -1 {
        return
    }
    f := make([]int, n)
    f[n-1] = coins[n-1]
    const inf = 1 << 30
    for i := n - 2; i >= 0; i-- {
        f[i] = inf
        if coins[i] != -1 {
            for j := i + 1; j < n && j < i+maxJump+1; j++ {
                if f[i] > f[j]+coins[i] {
                    f[i] = f[j] + coins[i]
                }
            }
        }
    }
    if f[0] == inf {
        return
    }
    for i, s := 0, f[0]; i < n; i++ {
        if f[i] == s {
            s -= coins[i]
            ans = append(ans, i+1)
        }
    }
    return
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function cheapestJump(coins: number[], maxJump: number): number[] {
    const n = coins.length;
    const ans: number[] = [];
    if (coins[n - 1] == -1) {
        return ans;
    }
    const inf = 1 << 30;
    const f: number[] = new Array(n).fill(inf);
    f[n - 1] = coins[n - 1];
    for (let i = n - 2; i >= 0; --i) {
        if (coins[i] !== -1) {
            for (let j = i + 1; j < Math.min(n, i + maxJump + 1); ++j) {
                f[i] = Math.min(f[i], f[j] + coins[i]);
            }
        }
    }
    if (f[0] === inf) {
        return ans;
    }
    for (let i = 0, s = f[0]; i < n; ++i) {
        if (f[i] == s) {
            s -= coins[i];
            ans.push(i + 1);
        }
    }
    return ans;
}

评论