Minimum Number of Coins for Fruits

medium dynamic programming queue array

Problem

You are given a 0-indexed array prices where prices[i] is the coins needed to buy the (i+1)-th fruit. If you purchase the (i+1)-th fruit, you may take any number of the next i fruits for free. Even a fruit you could take for free may still be purchased to unlock its own reward. Return the minimum coins needed to acquire every fruit.

Inputprices = [3, 1, 2]
Output4
Buy fruit 1 (3 coins) → fruit 2 is free, but buying fruit 2 (1 coin) unlocks fruit 3 for free. Total = 3 + 1 = 4.

def minimumCoins(prices):
    n = len(prices)                          # number of fruits
    INF = float("inf")
    dp = [0] * (n + 2)                       # dp[i] uses 1-indexed fruits
    for i in range(n, 0, -1):                # fill from the last fruit back
        if 2 * i >= n:                       # buying fruit i reaches the end
            dp[i] = prices[i - 1]
        else:
            best = INF
            for j in range(i + 1, 2 * i + 2):  # next i fruits come free
                best = min(best, dp[j])      # cheapest place to resume buying
            dp[i] = prices[i - 1] + best     # pay for i, then continue
    return dp[1]                             # we must buy fruit 1 first
function minimumCoins(prices) {
  const n = prices.length;                   // number of fruits
  const INF = Infinity;
  const dp = new Array(n + 2).fill(0);       // dp[i] uses 1-indexed fruits
  for (let i = n; i >= 1; i--) {             // fill from the last fruit back
    if (2 * i >= n) {                        // buying fruit i reaches the end
      dp[i] = prices[i - 1];
    } else {
      let best = INF;
      for (let j = i + 1; j <= 2 * i + 1; j++) // next i fruits come free
        best = Math.min(best, dp[j]);        // cheapest place to resume buying
      dp[i] = prices[i - 1] + best;          // pay for i, then continue
    }
  }
  return dp[1];                              // we must buy fruit 1 first
}
int minimumCoins(int[] prices) {
    int n = prices.length;                   // number of fruits
    final int INF = Integer.MAX_VALUE;
    int[] dp = new int[n + 2];               // dp[i] uses 1-indexed fruits
    for (int i = n; i >= 1; i--) {           // fill from the last fruit back
        if (2 * i >= n) {                    // buying fruit i reaches the end
            dp[i] = prices[i - 1];
        } else {
            int best = INF;
            for (int j = i + 1; j <= 2 * i + 1; j++) // next i fruits come free
                best = Math.min(best, dp[j]); // cheapest place to resume buying
            dp[i] = prices[i - 1] + best;    // pay for i, then continue
        }
    }
    return dp[1];                            // we must buy fruit 1 first
}
int minimumCoins(vector<int>& prices) {
    int n = prices.size();                   // number of fruits
    const int INF = INT_MAX;
    vector<int> dp(n + 2, 0);                 // dp[i] uses 1-indexed fruits
    for (int i = n; i >= 1; i--) {           // fill from the last fruit back
        if (2 * i >= n) {                    // buying fruit i reaches the end
            dp[i] = prices[i - 1];
        } else {
            int best = INF;
            for (int j = i + 1; j <= 2 * i + 1; j++) // next i fruits come free
                best = min(best, dp[j]);     // cheapest place to resume buying
            dp[i] = prices[i - 1] + best;    // pay for i, then continue
        }
    }
    return dp[1];                            // we must buy fruit 1 first
}
Time: O(n²) Space: O(n)