Maximum Number of Eaten Apples — Medium Problem & Solution
A tree grows apples[i] apples on day i, and those apples rot after days[i] days — so they may be eaten on days i through i + days[i] - 1.
- Difficulty: Medium
- Topics: Arrays, Greedy, Heap
- Asked at: Amazon, Google, Swiggy
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
A tree grows apples[i] apples on day i, and those apples rot after days[i] days — so they may be eaten on days i through i + days[i] - 1. Some days it grows nothing, marked by apples[i] == 0 and days[i] == 0.
You eat at most one apple a day, and you may keep eating after day n - 1. Return the maximum number of apples you can eat.
Example 1
Input: apples = [1,2,3,5,2], days = [3,2,1,4,2]
Output: 7
Example 2
Input: apples = [3,0,0,0,0,2], days = [3,0,0,0,0,2]
Output: 5
Example 3
Input: apples = [2,1,10], days = [2,10,1]
Output: 4
Constraints
n == apples.length == days.length1 <= n <= 2 * 10^40 <= apples[i], days[i] <= 2 * 10^4days[i] == 0 if and only if apples[i] == 0.
How to solve Maximum Number of Eaten Apples
Greedy with a min-heap keyed on rot day. Each day, add that day's batch, throw away everything that has already rotted, and eat one apple from the batch that expires soonest.
Approach
- For day
i < nwithapples[i] > 0, push(i + days[i], apples[i]). - Discard every batch whose rot day is at most the current day.
- If anything is left, eat one apple from the soonest-rotting batch and drop it when it empties.
- Continue past day
n - 1while any batch survives.
Why it works
Eating from the soonest-rotting batch is optimal by an exchange argument: choosing any other batch today risks losing the sooner one entirely, while the later batch is still there tomorrow. The loop must run past n - 1, since apples grown on the last day may stay edible for a long time.
Complexity
- Time —
O((n + maxDays) log n) - Space —
O(n)
Pitfalls
- A batch rots on day
i + days[i], so it is edible up to the day before. - Stopping the loop at day
n - 1throws away still-edible apples. - Days with
apples[i] == 0add nothing but still count as a day you may eat on.
Reference solution
Python
from typing import List
import heapq
def eatenApples(apples: List[int], days: List[int]) -> int:
n = len(apples)
heap = []
eaten = 0
day = 0
while day < n or heap:
if day < n and apples[day] > 0:
heapq.heappush(heap, (day + days[day], apples[day]))
while heap and heap[0][0] <= day:
heapq.heappop(heap)
if heap:
rot, cnt = heapq.heappop(heap)
eaten += 1
if cnt - 1 > 0:
heapq.heappush(heap, (rot, cnt - 1))
day += 1
return eatenJavaScript
var eatenApples = function(apples, days) {
var n = apples.length;
var batch = [];
var eaten = 0, day = 0, i;
while (day < n || batch.length > 0) {
if (day < n && apples[day] > 0) batch.push([day + days[day], apples[day]]);
for (i = batch.length - 1; i >= 0; i--) {
if (batch[i][0] <= day) batch.splice(i, 1);
}
if (batch.length > 0) {
var best = 0;
for (i = 1; i < batch.length; i++) if (batch[i][0] < batch[best][0]) best = i;
batch[best][1]--;
eaten++;
if (batch[best][1] === 0) batch.splice(best, 1);
}
day++;
}
return eaten;
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.