leetcode
leetcode 1501 ~ 1550
吃苹果的最大数目

吃苹果的最大数目

难度:

标签:

题目描述

代码结果

运行时间: 151 ms, 内存: 20.4 MB


/*
 * 思路:
 * 1. 使用优先队列(PriorityQueue)来追踪苹果的数量和腐烂日期。
 * 2. 每天移除已经腐烂的苹果。
 * 3. 如果有新苹果生长,加入优先队列。
 * 4. 如果有可以吃的苹果,吃一个并更新优先队列中的数量。
 * 5. 使用Stream API处理数组元素。
 */
import java.util.*;
import java.util.stream.IntStream;

public class AppleEatingStream {
    public int eatenApples(int[] apples, int[] days) {
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        int[] indices = IntStream.range(0, apples.length).toArray();
        int day = 0;
        int eaten = 0;

        while (day < apples.length || !pq.isEmpty()) {
            if (day < apples.length && apples[day] > 0) {
                pq.offer(new int[]{day + days[day], apples[day]});
            }
            while (!pq.isEmpty() && pq.peek()[0] <= day) {
                pq.poll();
            }
            if (!pq.isEmpty()) {
                int[] current = pq.peek();
                current[1]--;
                if (current[1] == 0) {
                    pq.poll();
                }
                eaten++;
            }
            day++;
        }

        return eaten;
    }

    public static void main(String[] args) {
        AppleEatingStream aes = new AppleEatingStream();
        int[] apples = {1, 2, 3, 5, 2};
        int[] days = {3, 2, 1, 4, 2};
        System.out.println(aes.eatenApples(apples, days)); // 输出: 7
    }
}

解释

方法:

题解采用了贪心算法和优先队列(最小堆)来解决问题。每天都会检查新长出的苹果并记录它们腐烂的日期和数量。使用最小堆是为了每天都能优先吃掉最先腐烂的苹果。堆中每个元素是一个列表,其中第一个元素是苹果腐烂的日期,第二个元素是苹果的数量。每天开始时,会移除所有已经腐烂的苹果。如果当天有新苹果,就将其添加到堆中。接着,如果堆不为空,表示还有未腐烂的苹果,就吃掉一个,并相应地更新堆。遍历完所有的天数后,还需要处理堆中剩余的苹果,直到所有的苹果都被吃完或腐烂。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在处理剩余苹果的循环中,如何确定循环终止的条件,并保证所有可以吃的苹果都被正确计算?
在处理剩余苹果的循环中,循环终止的条件是堆为空。堆中存储了所有尚未腐烂的苹果及其腐烂日期。在每次循环中,从堆中取出最先腐烂的苹果(堆顶元素),计算可以吃的苹果数量,这是通过取腐烂日期与当前日期之差和苹果数量的较小值来决定的。吃完这些苹果或者达到腐烂日期,当前日期更新为腐烂日期或增加与吃苹果数量相等的天数。这样确保了所有可以吃的苹果都被正确计算,直到没有更多的苹果可以吃(即堆为空)。
🦆
在每日移除腐烂苹果的过程中,如果存在多个苹果在同一天腐烂,算法是如何确保所有这些苹果都被及时移除的?
算法在每天的开始使用一个循环来检查并移除所有已经腐烂的苹果。堆(最小堆)的顶部存储的是最早腐烂的苹果。在循环中,检查堆顶苹果的腐烂日期是否小于或等于当前天数。如果是,使用 `heappop` 函数从堆中移除这些苹果。循环继续,直到堆顶的苹果腐烂日期大于当前日期,确保了所有在当天或之前腐烂的苹果都被及时移除。
🦆
算法在添加新苹果到堆中时,是如何处理那些当天就会腐烂的苹果的?
在添加新苹果到堆中时,算法首先计算每批新苹果的腐烂日期(当前日期加上苹果的持续天数)。如果这个腐烂日期等于当前日期,这批苹果当天就会腐烂,因此,它们不会被添加到堆中,即避免了无用的操作。只有当腐烂日期大于当前日期时,这批苹果才被添加到堆中,这样确保了堆中只存储那些至少能存活到第二天的苹果。
🦆
考虑到每天只能吃一个苹果,当堆中存在多个苹果而其中一些即将在当天或次日腐烂时,算法是如何优先选择苹果的?
算法使用的最小堆自然地处理了这一优先选择问题。在最小堆中,堆顶元素总是腐烂日期最早的苹果。每天只能吃一个苹果时,直接从堆顶取苹果吃掉。这确保了优先吃掉那些即将在当天或次日腐烂的苹果,从而最大化苹果的使用效率并减少浪费。

相关问题