Problem Description
You are given a 1-indexed array prices where prices[i] is the number of coins required to purchase the iᵗʰ fruit. When you purchase the iᵗʰ fruit you gain an “offer” – you may take the next i fruits for free. (In other words, buying fruit i “covers” the fruits in the interval [i, min(n, i+i)].) Note that even if a fruit is available for free you always have the option to purchase it in order to gain a new offer. Return the minimum number of coins needed so that you acquire all the fruits.
For example, in prices = [3,1,2]: • Buying the 1ˢᵗ fruit costs 3 coins and gives you fruit 2 for free. • Even though fruit 2 is free you may choose to buy it (for 1 coin) to get fruit 3 for free. The minimum total cost is 4 coins.
Key Insights
- Think of a purchase at index j as “covering” fruits j through min(n, 2*j).
- The overall problem is to “cover” the indices 1…n with such intervals.
- Even if a fruit is available for free (i.e. already covered by a previous purchase) it might be optimal to purchase it if its price is low and its offer covers a larger range.
- A useful recurrence is to define dp[i] as the minimum cost to have acquired fruits 1 through i. Notice that fruit i is acquired if it lies in the interval [j, 2*j] for some purchased fruit j.
- In fact, one may show that for each i (1 ≤ i ≤ n) it holds that
dp[i] = min { dp[j–1] + prices[j] } for j = ceil(i/2) … i
because if fruit j was purchased then it “covers” fruits j through 2j (in particular i ≤ 2j must hold, equivalently j ≥ ceil(i/2)). - The naïve implementation of this recurrence is O(n²) but one may observe that for each i we want the minimum of A[j] = dp[j–1] + prices[j] over j in an interval [L, i] where L = ceil(i/2). This “range‐minimum query” can be answered in O(log n) time by a segment tree.
Space and Time Complexity
Time Complexity: O(n log n), where n is the number of fruits (using a segment tree for range minimum queries).
Space Complexity: O(n) for the dp array and the segment tree.
Solution
We first derive a recurrence for dp:
For i = 1…n, dp[i] is the minimum coins required to cover fruits 1 to i. Notice that if we purchase fruit j (1 ≤ j ≤ i) then fruit j and the next j fruits (up to index 2j) are acquired. Thus, i is “covered” if i ≤ 2j. In other words, in order for fruit j’s purchase to cover fruit i we must have j ≥ ceil(i/2). Hence the recurrence is
dp[i] = min { dp[j – 1] + prices[j] } for all j in [ceil(i/2), i].
We then define an auxiliary array A where A[j] = dp[j – 1] + prices[j]. Once dp[0] is known (set to 0) we can “fill” dp[1…n] in increasing order. Since for each i we need the minimum A[j] over j in an interval [ceil(i/2), i] a segment tree (or similar structure) is used so that each query runs in O(log n) time. Finally, answer = dp[n].
Below are code solutions in four languages. Each solution uses a segment tree (with point‐updates and range minimum queries) so that the recurrence is computed efficiently.