1705. 吃苹果的最大数目
题干
有一棵特殊的苹果树,一连 n 天,每天都可以长出若干个苹果。在第 i 天,树上会长出 apples[i] 个苹果,这些苹果将会在 days[i] 天后(也就是说,第 i + days[i] 天时)腐烂,变得无法食用。也可能有那么几天,树上不会长出新的苹果,此时用 apples[i] == 0 且 days[i] == 0 表示。
你打算每天 最多 吃一个苹果来保证营养均衡。注意,你可以在这 n 天之后继续吃苹果。
给你两个长度为 n 的整数数组 days 和 apples ,返回你可以吃掉的苹果的最大数目。
示例 1:
输入:
apples = [1,2,3,5,2],
days = [3,2,1,4,2]
输出:7
解释:你可以吃掉 7 个苹果:
- 第一天,你吃掉第一天长出来的苹果。
- 第二天,你吃掉一个第二天长出来的苹果。
- 第三天,你吃掉一个第二天长出来的苹果。过了这一天,第三天长出来的苹果就已经腐烂了。
- 第四天到第七天,你吃的都是第四天长出来的苹果。
示例 2:
输入:
apples = [3,0,0,0,0,2],
days = [3,0,0,0,0,2]
输出:5
解释:你可以吃掉 5 个苹果:
- 第一天到第三天,你吃的都是第一天长出来的苹果。
- 第四天和第五天不吃苹果。
- 第六天和第七天,你吃的都是第六天长出来的苹果。
提示:
apples.length == n
days.length == n
1 <= n <= 2 * 104
0 <= apples[i], days[i] <= 2 * 104
只有在 apples[i] = 0 时,days[i] = 0 才成立
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-number-of-eaten-apples
解题思路
核心的思路就是:先吃快到期的苹果。
我们可以创建优先队列来记录每个苹果的过期日期。
其中,优先队列中最小的元素(就是,最早的腐烂日期)会最先被取出。
按照题意可以将吃苹果分为两个阶段
-
边吃边存(苹果树每天产新苹果)
- 将优先队列中的所有保质期小于等于当前日期的元素取出,这些是已经烂掉的苹果,没法吃;
- 根据题目给的俩数组判断是否有新苹果,有了,就把他的保质期存进队列中。
- 把队列(苹果篮)整理好后,就可以享受当天的苹果了。
-
只吃存的(苹果树不产苹果了)
只需要吃了。
可以根据当前日期和队列中的队首元素的腐烂日期和数量计算能吃到的苹果数量。
同样的思路,
代码
class Solution {
public int eatenApples(int[] apples, int[] days) {
int len = apples.length;
//记录有效的苹果过期日期数
PriorityQueue<Integer> queue = new PriorityQueue<>();
//每个过期日期还剩的苹果
Map<Integer, Integer> map = new HashMap<>();
int res = 0;
int i = 0;
//苹果树还能长苹果 或 还没坏的苹果
while (i < len || !queue.isEmpty()){
//去掉过时的烂苹果
while (!queue.isEmpty() && queue.peek() < i){
map.remove(queue.poll());
}
//加入新苹果
if (i < len && apples[i] > 0){
int lastEatDay = i + days[i] - 1;
if (map.containsKey(lastEatDay)){
map.put(lastEatDay, map.get(lastEatDay) + apples[i]);
} else {
map.put(lastEatDay, apples[i]);
queue.add(lastEatDay);
}
}
//开始吃苹果
if (!queue.isEmpty()){
res++;
Integer eatDay = queue.poll();
Integer count = map.get(eatDay);
if (count > 1 && eatDay > i){
//苹果吃不完 且 苹果过期时间是今天之后
queue.add(eatDay);
map.put(eatDay, count - 1);
} else {
//苹果吃完了 或 今天后这一批苹果过期
map.remove(eatDay);
}
}
//下一天
i++;
}
return res;
}
}