The Jump Game VIII problem builds on the classic Jump Game series. You are given an array nums
of length n
, where each element nums[i]
represents the maximum number of steps you can jump forward from that position. In this version, there may also be an array cost
of the same length, where cost[i]
is the cost of jumping from index i
. Your goal is to determine the minimum total cost to reach the last index of the array, starting from the first index (index 0
).
i
to any index j
such that i < j ≤ i + nums[i]
.cost[j]
for landing at index j
(sometimes the cost may be paid at the source, depending on the exact problem variant; here, we assume the cost is at the destination).-1
.1 ≤ n ≤ 10^5
, 0 ≤ nums[i] ≤ n
, 0 ≤ cost[i] ≤ 10^9
.
At first glance, the problem resembles the classic Jump Game, but the added cost
array means we must optimize for minimal cost, not just reachability. A brute-force approach would be to try every possible jump from every index and keep track of the minimum cost to reach each position. However, this would be very slow for large arrays.
The problem now resembles the "shortest path" problem in a graph, where each index is a node, and you can jump from node i
to nodes j
with a directed edge of cost cost[j]
. The goal is to find the minimum cost path from node 0
to node n-1
. This suggests using algorithms like Dijkstra's algorithm, which is efficient for finding shortest paths in graphs with non-negative edge weights.
The main challenge is efficiently processing possible jumps, as each node can have up to nums[i]
outgoing edges. We need a way to avoid redundant calculations and keep the algorithm efficient.
We can model the problem as a graph and use a priority queue (min-heap) to always process the currently reachable node with the lowest total cost so far. Here is a step-by-step breakdown:
min_cost
of size n
to store the minimum cost to reach each index. Initialize all values to infinity, except min_cost[0] = cost[0]
(since we start at index 0 and pay its cost).(min_cost[0], 0)
onto it.i
(i.e., for each j
in [i+1, min(i+nums[i], n-1)]
):min_cost[j] > curr_cost + cost[j]
, update min_cost[j]
and push (min_cost[j], j)
onto the heap.min_cost[n-1]
. If it is still infinity, return -1
(unreachable); otherwise, return min_cost[n-1]
.This approach is efficient because the heap ensures we always expand the lowest-cost paths first, and we never revisit a node with a higher cost than previously found.
Suppose nums = [2,3,1,1,4]
and cost = [1,2,4,1,3]
.
min_cost[0] = 1
.min_cost[1] = 3
min_cost[2] = 5
min_cost[2]
is already 5, so skip)min_cost[3] = 4
min_cost[4] = 6
min_cost[4]
is already 6, so skip)min_cost[3]
is already 4, so skip)The answer is 6.
nums[i]
, but in the worst case (if all nums[i]
= n), it can approach O(n^2).min_cost
array and heap.The Jump Game VIII problem extends the classic jump game by adding costs, turning it into a shortest path problem on a graph. By modeling the array as a graph and using Dijkstra's algorithm with a min-heap, we efficiently compute the minimum cost to reach the last index. The solution leverages greedy expansion and efficient updates to guarantee the minimum cost path, making it both elegant and practical for large input sizes.
import heapq
def minCostJump(nums, cost):
n = len(nums)
min_cost = [float('inf')] * n
min_cost[0] = cost[0]
heap = [(cost[0], 0)]
while heap:
curr_cost, i = heapq.heappop(heap)
if i == n - 1:
return curr_cost
if curr_cost > min_cost[i]:
continue
for j in range(i + 1, min(i + nums[i] + 1, n)):
new_cost = curr_cost + cost[j]
if new_cost < min_cost[j]:
min_cost[j] = new_cost
heapq.heappush(heap, (new_cost, j))
return -1
#include <vector>
#include <queue>
#include <limits>
using namespace std;
int minCostJump(vector<int>& nums, vector<int>& cost) {
int n = nums.size();
vector<long long> min_cost(n, LLONG_MAX);
min_cost[0] = cost[0];
priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;
pq.push({cost[0], 0});
while (!pq.empty()) {
auto [curr_cost, i] = pq.top(); pq.pop();
if (i == n - 1) return curr_cost;
if (curr_cost > min_cost[i]) continue;
for (int j = i + 1; j <= min(i + nums[i], n - 1); ++j) {
long long new_cost = curr_cost + cost[j];
if (new_cost < min_cost[j]) {
min_cost[j] = new_cost;
pq.push({new_cost, j});
}
}
}
return -1;
}
import java.util.*;
public class Solution {
public int minCostJump(int[] nums, int[] cost) {
int n = nums.length;
long[] minCost = new long[n];
Arrays.fill(minCost, Long.MAX_VALUE);
minCost[0] = cost[0];
PriorityQueue<long[]> pq = new PriorityQueue<>(Comparator.comparingLong(a -> a[0]));
pq.offer(new long[]{cost[0], 0});
while (!pq.isEmpty()) {
long[] curr = pq.poll();
long currCost = curr[0];
int i = (int)curr[1];
if (i == n - 1) return (int)currCost;
if (currCost > minCost[i]) continue;
for (int j = i + 1; j <= Math.min(i + nums[i], n - 1); ++j) {
long newCost = currCost + cost[j];
if (newCost < minCost[j]) {
minCost[j] = newCost;
pq.offer(new long[]{newCost, j});
}
}
}
return -1;
}
}
class MinHeap {
constructor() {
this.heap = [];
}
push(val) {
this.heap.push(val);
this._bubbleUp(this.heap.length - 1);
}
pop() {
if (this.heap.length === 1) return this.heap.pop();
const top = this.heap[0];
this.heap[0] = this.heap.pop();
this._bubbleDown(0);
return top;
}
_bubbleUp(idx) {
while (idx > 0) {
const parent = Math.floor((idx - 1) / 2);
if (this.heap[parent][0] <= this.heap[idx][0]) break;
[this.heap[parent], this.heap[idx]] = [this.heap[idx], this.heap[parent]];
idx = parent;
}
}
_bubbleDown(idx) {
const n = this.heap.length;
while (true) {
let smallest = idx;
const left = 2 * idx + 1, right = 2 * idx + 2;
if (left < n && this.heap[left][0] < this.heap[smallest][0]) smallest = left;
if (right < n && this.heap[right][0] < this.heap[smallest][0]) smallest = right;
if (smallest === idx) break;
[this.heap[smallest], this.heap[idx]] = [this.heap[idx], this.heap[smallest]];
idx = smallest;
}
}
isEmpty() {
return this.heap.length === 0;
}
}
function minCostJump(nums, cost) {
const n = nums.length;
const minCost = Array(n).fill(Infinity);
minCost[0] = cost[0];
const heap = new MinHeap();
heap.push([cost[0], 0]);
while (!heap.isEmpty()) {
const [currCost, i] = heap.pop();
if (i === n - 1) return currCost;
if (currCost > minCost[i]) continue;
for (let j = i + 1; j <= Math.min(i + nums[i], n - 1); ++j) {
const newCost = currCost + cost[j];
if (newCost < minCost[j]) {
minCost[j] = newCost;
heap.push([newCost, j]);
}
}
}
return -1;
}