Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
There is a special kind of apple tree that grows apples every day for n days. On the ith day, the tree grows apples[i] apples that will rot after days[i] days, that is on day i + days[i] the apples will be rotten and cannot be eaten. On some days, the apple tree does not grow any apples, which are denoted by apples[i] == 0 and days[i] == 0.
You decided to eat at most one apple a day (to keep the doctors away). Note that you can keep eating after the first n days.
Given two integer arrays days and apples of length n, 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 Explanation: You can eat 7 apples: - On the first day, you eat an apple that grew on the first day. - On the second day, you eat an apple that grew on the second day. - On the third day, you eat an apple that grew on the second day. After this day, the apples that grew on the third day rot. - On the fourth to the seventh days, you eat apples that grew on the fourth day.
Example 2:
Input: apples = [3,0,0,0,0,2], days = [3,0,0,0,0,2] Output: 5 Explanation: You can eat 5 apples: - On the first to the third day you eat apples that grew on the first day. - Do nothing on the fouth and fifth days. - On the sixth and seventh days you eat apples that grew on the sixth day.
Constraints:
n == apples.length == days.length1 <= n <= 2 * 1040 <= apples[i], days[i] <= 2 * 104days[i] = 0 if and only if apples[i] = 0.Problem summary: There is a special kind of apple tree that grows apples every day for n days. On the ith day, the tree grows apples[i] apples that will rot after days[i] days, that is on day i + days[i] the apples will be rotten and cannot be eaten. On some days, the apple tree does not grow any apples, which are denoted by apples[i] == 0 and days[i] == 0. You decided to eat at most one apple a day (to keep the doctors away). Note that you can keep eating after the first n days. Given two integer arrays days and apples of length n, return the maximum number of apples you can eat.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Greedy
[1,2,3,5,2] [3,2,1,4,2]
[3,0,0,0,0,2] [3,0,0,0,0,2]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1705: Maximum Number of Eaten Apples
class Solution {
public int eatenApples(int[] apples, int[] days) {
PriorityQueue<int[]> q = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
int n = days.length;
int ans = 0, i = 0;
while (i < n || !q.isEmpty()) {
if (i < n && apples[i] > 0) {
q.offer(new int[] {i + days[i] - 1, apples[i]});
}
while (!q.isEmpty() && q.peek()[0] < i) {
q.poll();
}
if (!q.isEmpty()) {
var p = q.poll();
++ans;
if (--p[1] > 0 && p[0] > i) {
q.offer(p);
}
}
++i;
}
return ans;
}
}
// Accepted solution for LeetCode #1705: Maximum Number of Eaten Apples
func eatenApples(apples []int, days []int) int {
var h hp
ans, n := 0, len(apples)
for i := 0; i < n || len(h) > 0; i++ {
if i < n && apples[i] > 0 {
heap.Push(&h, pair{i + days[i] - 1, apples[i]})
}
for len(h) > 0 && h[0].first < i {
heap.Pop(&h)
}
if len(h) > 0 {
h[0].second--
if h[0].first == i || h[0].second == 0 {
heap.Pop(&h)
}
ans++
}
}
return ans
}
type pair struct {
first int
second int
}
type hp []pair
func (a hp) Len() int { return len(a) }
func (a hp) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a hp) Less(i, j int) bool { return a[i].first < a[j].first }
func (a *hp) Push(x any) { *a = append(*a, x.(pair)) }
func (a *hp) Pop() any { l := len(*a); t := (*a)[l-1]; *a = (*a)[:l-1]; return t }
# Accepted solution for LeetCode #1705: Maximum Number of Eaten Apples
class Solution:
def eatenApples(self, apples: List[int], days: List[int]) -> int:
n = len(days)
i = ans = 0
q = []
while i < n or q:
if i < n and apples[i]:
heappush(q, (i + days[i] - 1, apples[i]))
while q and q[0][0] < i:
heappop(q)
if q:
t, v = heappop(q)
v -= 1
ans += 1
if v and t > i:
heappush(q, (t, v))
i += 1
return ans
// Accepted solution for LeetCode #1705: Maximum Number of Eaten Apples
struct Solution;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
impl Solution {
fn eaten_apples(apples: Vec<i32>, days: Vec<i32>) -> i32 {
let n = apples.len();
let mut queue: BinaryHeap<Reverse<(usize, i32)>> = BinaryHeap::new();
let mut i = 0;
let mut res = 0;
loop {
if i < n {
queue.push(Reverse((i + days[i] as usize, apples[i])));
}
if i >= n && queue.is_empty() {
break;
}
while let Some(Reverse((j, left))) = queue.peek() {
if i >= *j || *left == 0 {
queue.pop();
} else {
break;
}
}
if let Some(mut top) = queue.peek_mut() {
(top.0).1 -= 1;
res += 1;
}
i += 1;
}
res
}
}
#[test]
fn test() {
let apples = vec![1, 2, 3, 5, 2];
let days = vec![3, 2, 1, 4, 2];
let res = 7;
assert_eq!(Solution::eaten_apples(apples, days), res);
let apples = vec![3, 0, 0, 0, 0, 2];
let days = vec![3, 0, 0, 0, 0, 2];
let res = 5;
assert_eq!(Solution::eaten_apples(apples, days), res);
}
// Accepted solution for LeetCode #1705: Maximum Number of Eaten Apples
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #1705: Maximum Number of Eaten Apples
// class Solution {
// public int eatenApples(int[] apples, int[] days) {
// PriorityQueue<int[]> q = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
// int n = days.length;
// int ans = 0, i = 0;
// while (i < n || !q.isEmpty()) {
// if (i < n && apples[i] > 0) {
// q.offer(new int[] {i + days[i] - 1, apples[i]});
// }
// while (!q.isEmpty() && q.peek()[0] < i) {
// q.poll();
// }
// if (!q.isEmpty()) {
// var p = q.poll();
// ++ans;
// if (--p[1] > 0 && p[0] > i) {
// q.offer(p);
// }
// }
// ++i;
// }
// return ans;
// }
// }
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.