Minimum Number of Coins for Fruits

MEDIUM

Description

You are given an 0-indexed integer array prices where prices[i] denotes the number of coins needed to purchase the (i + 1)th fruit.

The fruit market has the following reward for each fruit:

  • If you purchase the (i + 1)th fruit at prices[i] coins, you can get any number of the next i fruits for free.

Note that even if you can take fruit j for free, you can still purchase it for prices[j - 1] coins to receive its reward.

Return the minimum number of coins needed to acquire all the fruits.

 

Example 1:

Input: prices = [3,1,2]

Output: 4

Explanation:

  • Purchase the 1st fruit with prices[0] = 3 coins, you are allowed to take the 2nd fruit for free.
  • Purchase the 2nd fruit with prices[1] = 1 coin, you are allowed to take the 3rd fruit for free.
  • Take the 3rd fruit for free.

Note that even though you could take the 2nd fruit for free as a reward of buying 1st fruit, you purchase it to receive its reward, which is more optimal.

Example 2:

Input: prices = [1,10,1,1]

Output: 2

Explanation:

  • Purchase the 1st fruit with prices[0] = 1 coin, you are allowed to take the 2nd fruit for free.
  • Take the 2nd fruit for free.
  • Purchase the 3rd fruit for prices[2] = 1 coin, you are allowed to take the 4th fruit for free.
  • Take the 4th fruit for free.

Example 3:

Input: prices = [26,18,6,12,49,7,45,45]

Output: 39

Explanation:

  • Purchase the 1st fruit with prices[0] = 26 coin, you are allowed to take the 2nd fruit for free.
  • Take the 2nd fruit for free.
  • Purchase the 3rd fruit for prices[2] = 6 coin, you are allowed to take the 4th, 5th and 6th (the next three) fruits for free.
  • Take the 4th fruit for free.
  • Take the 5th fruit for free.
  • Purchase the 6th fruit with prices[5] = 7 coin, you are allowed to take the 8th and 9th fruit for free.
  • Take the 7th fruit for free.
  • Take the 8th fruit for free.

Note that even though you could take the 6th fruit for free as a reward of buying 3rd fruit, you purchase it to receive its reward, which is more optimal.

 

Constraints:

  • 1 <= prices.length <= 1000
  • 1 <= prices[i] <= 105

Approaches

Checkout 2 different approaches to solve Minimum Number of Coins for Fruits. Click on different approaches to view the approach and algorithm in detail.

Bottom-Up Dynamic Programming

This problem exhibits optimal substructure and overlapping subproblems, making it a good candidate for dynamic programming. We can define a DP state dp[i] as the minimum cost to acquire the first i fruits. Our goal is to find dp[n], the minimum cost for all n fruits.

The base case is dp[0] = 0, as acquiring no fruits costs nothing.

To compute dp[i], we must ensure fruit i is acquired. This can happen if we buy fruit i, or if we get it for free from a prior purchase. We can generalize this by considering that to acquire fruit i, we must have bought some fruit k (where 1 <= k <= i) that 'covers' fruit i. Buying fruit k (at index k-1) gives fruits k+1 through 2k for free. Thus, fruit k covers fruit i if k=i or k+1 <= i <= 2k. The latter condition simplifies to ceil(i/2) <= k <= i-1.

So, to find dp[i], we can take the minimum over all valid choices of k from ceil(i/2) to i. For each such k, the cost is the price of fruit k (prices[k-1]) plus the minimum cost to acquire fruits 1 to k-1 (dp[k-1]). This gives the recurrence relation:

dp[i] = min_{k=ceil(i/2)}^{i} (dp[k-1] + prices[k-1])

We can implement this by iterating i from 1 to n and, for each i, iterating k through its valid range to find the minimum cost.

Algorithm

  • Create a DP array dp of size n+1, where n is the number of fruits.
  • Initialize dp[0] = 0, and other elements to a large value.
  • Iterate i from 1 to n to compute dp[i], the minimum cost to acquire fruits 1 through i.
  • For each i, calculate the cost by considering all possible fruits k (from ceil(i/2) to i) that could be purchased to cover fruit i.
  • The cost of purchasing fruit k is prices[k-1], and we must have already acquired fruits 1 to k-1 with a minimum cost of dp[k-1]. The total cost for this choice is dp[k-1] + prices[k-1].
  • Update dp[i] with the minimum cost found among all valid choices of k.
  • The final answer is dp[n].

We use a bottom-up dynamic programming approach. Let dp[i] be the minimum cost to obtain the first i fruits (using 1-based indexing for fruits, so i ranges from 1 to n). The size of our dp array will be n+1.

  • Initialization: dp[0] = 0. All other dp values can be initialized to infinity.

  • Recurrence: To calculate dp[i], we consider all possible fruits k we could have purchased that would cover fruit i. A purchase of fruit k covers fruit i if i is k itself, or if i is one of the free fruits obtained from buying k (i.e., k+1 <= i <= 2k). This gives a range for k from ceil(i/2) to i. For any such k, the total cost would be the cost to acquire fruits up to k-1 (dp[k-1]) plus the cost of fruit k (prices[k-1]). We take the minimum over all these possibilities.

dp[i] = min(dp[k-1] + prices[k-1]) for k in [ceil(i/2), i]

  • Final Answer: The minimum cost to acquire all n fruits is dp[n].

Here is the Java implementation:

class Solution {
    public int minimumCoins(int[] prices) {
        int n = prices.length;
        int[] dp = new int[n + 1];
        // dp[i] = min cost to acquire first i fruits (1-based index)
        
        dp[0] = 0;
        
        for (int i = 1; i <= n; i++) {
            dp[i] = Integer.MAX_VALUE;
            // To acquire fruit i, we must buy some fruit k (1-based)
            // such that buying k covers i.
            // This means k=i, or k+1 <= i <= 2k.
            // The range for k is [ceil(i/2), i].
            // For positive integers, ceil(i/2) is (i+1)/2 using integer division.
            int start_k = (i + 1) / 2;
            for (int k = start_k; k <= i; k++) {
                // Cost of buying fruit k is prices[k-1].
                // We must have acquired fruits 1...k-1, which costs dp[k-1].
                // Total cost for this choice is dp[k-1] + prices[k-1].
                dp[i] = Math.min(dp[i], dp[k - 1] + prices[k - 1]);
            }
        }
        
        return dp[n];
    }
}

Complexity Analysis

Time Complexity: O(n^2) - We have a nested loop structure. The outer loop runs `n` times (for `i` from 1 to `n`), and the inner loop runs up to `i/2` times (for `k` from `ceil(i/2)` to `i`). This results in a total time complexity proportional to the sum of `i/2` from `i=1` to `n`, which is `O(n^2)`.Space Complexity: O(n) - We use a DP array of size `n+1` to store the minimum costs.

Pros and Cons

Pros:
  • Relatively straightforward to understand and implement based on the DP recurrence relation.
  • Correctly solves the problem for the given constraints.
Cons:
  • The time complexity is quadratic, which can be slow for larger constraints (though it passes for n=1000).

Code Solutions

Checking out 3 solutions in different languages for Minimum Number of Coins for Fruits. Click on different languages to view the code.


Video Solution

Watch the video walkthrough for Minimum Number of Coins for Fruits



Patterns:

Dynamic Programming

Data Structures:

ArrayHeap (Priority Queue)QueueMonotonic Queue

Subscribe to Scale Engineer newsletter

Learn about System Design, Software Engineering, and interview experiences every week.

No spam, unsubscribe at any time.