给定一个数组 A
(下标从 1
开始)包含 N 个整数:A1,A2,……,AN 和一个整数 B
。你可以从数组 A
中的任何一个位置(下标为 i
)跳到下标 i+1
,i+2
,……,i+B
的任意一个可以跳到的位置上。如果你在下标为 i
的位置上,你需要支付 Ai 个金币。如果 Ai 是 -1,意味着下标为 i
的位置是不可以跳到的。
现在,你希望花费最少的金币从数组 A
的 1
位置跳到 N
位置,你需要输出花费最少的路径,依次输出所有经过的下标(从 1 到 N)。
如果有多种花费最少的方案,输出字典顺序最小的路径。
如果无法到达 N 位置,请返回一个空数组。
样例 1 :
输入: [1,2,4,-1,2], 2 输出: [1,3,5]
样例 2 :
输入: [1,2,4,-1,2], 1 输出: []
注释 :
- 路径 Pa1,Pa2,……,Pan 是字典序小于 Pb1,Pb2,……,Pbm 的,当且仅当第一个 Pai 和 Pbi 不同的
i
满足 Pai < Pbi,如果不存在这样的i
那么满足n
<m
。 - A1 >= 0。 A2, ..., AN (如果存在) 的范围是 [-1, 100]。
- A 数组的长度范围 [1, 1000].
- B 的范围 [1, 100].
方法一:动态规划(逆向)
题目需要我们找到从下标 1 到下标 n 的最小花费路径,且字典序最小,我们可以使用动态规划求解。
我们定义
接下来,我们从下标
然后我们判断
时间复杂度
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
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;
}
}
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;
}
};
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
}
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;
}