LeetCode 1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解

【LetMeFly】1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解

力扣题目链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/

有一棵特殊的苹果树,一连 n 天,每天都可以长出若干个苹果。在第 i 天,树上会长出 apples[i] 个苹果,这些苹果将会在 days[i] 天后(也就是说,第 i + days[i] 天时)腐烂,变得无法食用。也可能有那么几天,树上不会长出新的苹果,此时用 apples[i] == 0days[i] == 0 表示。

你打算每天 最多 吃一个苹果来保证营养均衡。注意,你可以在这 n 天之后继续吃苹果。

给你两个长度为 n 的整数数组 daysapples ,返回你可以吃掉的苹果的最大数目*。*

示例 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 * 10^4^
  • 0 <= apples[i], days[i] <= 2 * 10^4^
  • 只有在 apples[i] = 0 时,days[i] = 0 才成立

解题方法:贪心

思路很简单:

有一些苹果,你先吃哪个?答案是先吃腐烂最早的。

因此可以使用优先队列,从第0天开始模拟到第 n − 1 n-1 n−1天:

每天将当天新苹果入队;腐烂较早的最优先;

队列不空今天还没吃到苹果时不断出队,若已腐烂则丢弃,若未腐烂则吃一个并将剩下的苹果入队。

遍历完 0 0 0到 n − 1 n-1 n−1天,不再有新苹果了,但队列中可能有旧苹果。

这次和之前有所不同,不再一天一天吃,而是几天几天连续算:

假设当前是第 d a y day day天,队首苹果有 a p p l e N u m appleNum appleNum个且将在 r o t D a y rotDay rotDay腐烂,则能连续吃 m a x ( 0 , m i n ( r o t D a y − d a y , a p p l e N u m ) ) max(0, min(rotDay - day, appleNum)) max(0,min(rotDay−day,appleNum))天。

为什么 0 0 0到 n − 1 n-1 n−1天要一天一天地吃,而从第 n n n天开始可以连续吃同一批苹果?

因为从第 n n n天开始不会产生新苹果了,我们不再关心苹果的"产生日期",只要没过保质期就能吃。

但是前 n n n天可不一样,例如第 0 0 0天产 2 2 2个 1000 1000 1000天保质期的苹果,第 1 1 1天产 1 1 1个保质期 1 1 1天的苹果,那么就不能照着第 0 0 0天的 2 2 2个连续吃完,而应该第 0 0 0和 3 3 3天吃第 0 0 0天产的,第 1 1 1天吃第 1 1 1天产的。

本质上来说就是前 n n n天每天都有新苹果产生,可能导致队首苹果不再是腐烂最早的苹果。

  • 时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)
  • 空间复杂度 O ( n ) O(n) O(n)

AC代码

C++
cpp 复制代码
/*
 * @Author: LetMeFly
 * @Date: 2024-12-24 10:56:16
 * @LastEditors: LetMeFly.xyz
 * @LastEditTime: 2024-12-24 18:41:09
 */
// 不能只按照腐烂截止时间
// 例如不能为了吃截止时间为6的4,5而空出第3天
/*
[1,2,3,5,2]
[3,2,1,4,2]


<0-3, 1>, <1-3, 2>, <2-3, 1>, <3-7, 5>, <4-6, 2>
    0        1, 2                3, 6     4, 5
*/
// 前n天应该 边遍历边入队
class Solution {
public:
    int eatenApples(vector<int>& apples, vector<int>& days) {
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
        int ans = 0, day = 0;
        for (; day < apples.size(); day++) {
            if (apples[day]) {
                pq.push({day + days[day], apples[day]});
            }
            while (pq.size()) {
                auto [rotDay, appleNum] = pq.top();
                pq.pop();
                if (rotDay <= day) {
                    continue;
                }
                ans++;
                appleNum--;
                if (appleNum) {
                    pq.push({rotDay, appleNum});
                }
                break;
            }
        }
        while (pq.size()) {
            auto [rotDay, appleNum] = pq.top();
            pq.pop();
            int eat = max(0, min(rotDay - day, appleNum));
            ans += eat;
            day += eat;
        }
        return ans;
    }
};
Python
python 复制代码
'''
Author: LetMeFly
Date: 2024-12-24 18:46:52
LastEditors: LetMeFly.xyz
LastEditTime: 2024-12-24 18:56:55
'''
from typing import List
import heapq

class Solution:
    def eatenApples(self, apples: List[int], days: List[int]) -> int:
        pq = []
        ans = 0
        for day in range(len(apples)):
            if apples[day]:
                heapq.heappush(pq, (day + days[day], apples[day]))
            while pq:
                rotDay, appleNum = heapq.heappop(pq)
                if rotDay <= day:
                    continue
                ans += 1
                appleNum -= 1
                if appleNum:
                    heapq.heappush(pq, (rotDay, appleNum))
                break
        day += 1  # 注意这里和C不一样,python执行完day是能取到的右值
        while pq:
            rotDay, appleNum = heapq.heappop(pq)
            eat = max(0, min(rotDay - day, appleNum))
            ans += eat
            day += eat
        return ans
Java
java 复制代码
/*
 * @Author: LetMeFly
 * @Date: 2024-12-24 18:58:06
 * @LastEditors: LetMeFly.xyz
 * @LastEditTime: 2024-12-24 19:07:07
 */
import java.util.PriorityQueue;

class Solution {
    public int eatenApples(int[] apples, int[] days) {
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> a[0] - b[0]);
        int ans = 0, day = 0;
        for (; day < apples.length; day++) {
            if (apples[day] > 0) {
                pq.add(new int[]{day + days[day], apples[day]});
            }
            while (pq.size() > 0) {
                int[] temp = pq.poll();
                int rotDay = temp[0], appleNum = temp[1];
                if (rotDay <= day) {
                    continue;
                }
                ans++;
                appleNum--;
                if (appleNum > 0) {
                    pq.add(new int[]{rotDay, appleNum});
                }
                break;
            }
        }
        while (!pq.isEmpty()) {
            int[] temp = pq.poll();
            int rotDay = temp[0], appleNum = temp[1];
            int eat = Math.max(0, Math.min(rotDay - day, appleNum));
            ans += eat;
            day += eat;
        }
        return ans;
    }
}
Go
go 复制代码
/*
 * @Author: LetMeFly
 * @Date: 2024-12-24 19:07:32
 * @LastEditors: LetMeFly.xyz
 * @LastEditTime: 2024-12-24 23:43:52
 */
package main
import "container/heap"

type pair struct{ rotDay, appleNum int}
type PQ []pair

func (pq PQ) Len() int           { return len(pq) }
func (pq PQ) Less(i, j int) bool { return pq[i].rotDay < pq[j].rotDay }
func (pq PQ) Swap(i, j int)      { pq[i], pq[j] = pq[j], pq[i] }
func (pq *PQ) Push(v any)        { *pq = append(*pq, v.(pair)) }
func (pq *PQ) Pop() any          { v := (*pq)[len(*pq) - 1]; *pq = (*pq)[:len(*pq) - 1]; return v }

func min_eatenApples(a, b int) int { if a < b { return a}; return b}
func max_eatenApples(a, b int) int { if a > b { return a}; return b}

func eatenApples(apples []int, days []int) (ans int) {
    var pq PQ
    for day := range apples {
        if apples[day] > 0 {
            heap.Push(&pq, pair{day + days[day], apples[day]})
        }
        for len(pq) > 0 {
            v := heap.Pop(&pq).(pair)
            rotDay, appleNum := v.rotDay, v.appleNum
            if rotDay <= day {
                continue
            }
            ans++
            appleNum--
            if appleNum > 0 {
                heap.Push(&pq, pair{rotDay, appleNum})
            }
            break
        }
    }
    day := len(apples)
    for len(pq) > 0 {
        v := heap.Pop(&pq).(pair)
        rotDay, appleNum := v.rotDay, v.appleNum
        eat := max_eatenApples(0, min_eatenApples(rotDay - day, appleNum))
        ans += eat
        day += eat
    }
    return
}

Golang的堆是一个接口,需要实现Len、Less、Swap、Push、Pop方法。

可参考与ChatGPT的对话

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

Tisfy:https://letmefly.blog.csdn.net/article/details/144705583

相关推荐
Kenneth風车34 分钟前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111
算法·机器学习·分类
eternal__day41 分钟前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
APP 肖提莫1 小时前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
OTWOL1 小时前
两道数组有关的OJ练习题
c语言·开发语言·数据结构·c++·算法
qq_433554541 小时前
C++ 面向对象编程:递增重载
开发语言·c++·算法
带多刺的玫瑰2 小时前
Leecode刷题C语言之切蛋糕的最小总开销①
java·数据结构·算法
巫师不要去魔法部乱说2 小时前
PyCharm专项训练5 最短路径算法
python·算法·pycharm
qystca2 小时前
洛谷 P11242 碧树 C语言
数据结构·算法
冠位观测者3 小时前
【Leetcode 热题 100】124. 二叉树中的最大路径和
数据结构·算法·leetcode
悲伤小伞3 小时前
C++_数据结构_详解二叉搜索树
c语言·数据结构·c++·笔记·算法