废不多说先链接:
力扣1705吃苹果的最大数目https://leetcode-cn.com/problems/maximum-number-of-eaten-apples/ 又是一题现实日常会碰到的问题。
这题对于我的难点在于实现,思路一开始便有了:
现实中处理类似问题也是类似思路(之前在食品企业工作,颇有感触):食品饮料这种快消品相对保质期短,生产和销售厂商一定会本着先进先出的原则,即优先售卖大日期的产品(临保质期)。不过其实往往生产日期过了个把月的产品已经不受经销商欢迎了,需要促销或者搭配各种政策活动才能卖的动,即便其保质期1年乃至2年。
扯远了,要达到先进先出的目的,我们需要知道当下我手里有什么产品,产品的到期日期和数量,然后优先消耗日期最大的产品,另外统计每天新生产的产品和消耗的产品维护数据即可。还是比较清晰明了的。
因为不想创建一个2W~4W长度大小的数组(题干里1 <= n <= 2 * 10000,
),起初的想法是用HashMap(近期刚学了集合)以到期日期(腐烂日期)为键,苹果数量为值,然后维护这个HashMap。不过需要面临的问题是它是无序的,需要我们手动实现排序,这样会很麻烦,也会有很多不必要的开销。0 <= apples[i], days[i] <= 2 * 10000
翻看大佬们的评论,学习到了Queue这个集合,配合Comparator使用,感觉非常适合解决此类问题!了解了用法之后实现起来十分简单!
代码如下:
package cn.daycode.leetcode;
import java.util.Comparator;
import java.util.PriorityQueue;
public class EatenApples {
public static void main(String[] args) {
Solution s = new Solution();
int[] apples = {1,2,3,5,2};
int[] days = {3,2,1,4,2};
System.out.println(s.atenApples(apples, days));
}
}
class Solution{
public int atenApples(int[] apples, int[] days) {
int count = 0; // 一共吃了count个苹果
// 构建一个队列,队列里的元素是一个int数组,其中[0]为苹果的腐烂日期(i+days[i]),[1]为该保质期剩余苹果数量
// Comparator.comparingInt(a -> a[0]) 代表队列按照int数组[0]从小到达排列的
// 也就意味着是按照苹果的腐烂日期由近到远排列(参考评论+百度到的)
// 感觉此题解出,之前有些题目没有思路,或者有思路但是实现不了的,似乎可以尝试了!
PriorityQueue<int[]> appleStore = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
int[] tempApples = null; // 临时变量:方便我们从队列里拿苹果吃
// i < apples.length代表苹果树还在生长阶段
// !appleStore.isEmpty()代表仓库还有没过期的苹果
// 两者有其一我们就继续尝试吃苹果
for (int i = 0; i < apples.length || !appleStore.isEmpty(); i++) {
// 苹果还在生长阶段的话,今天产了苹果就存进仓库
if(i<apples.length && days[i]>0){
appleStore.offer(new int[]{i+days[i], apples[i]});
}
// 检查保质期最近的苹果是否过期,过期就要丢掉(该保质期苹果吃完了的话也要poll)
while((tempApples = appleStore.peek()) !=null) {
if (tempApples[0] <= i || tempApples[1] == 0) {
appleStore.poll();
}else {
// 有能吃的苹果就吃掉1个,然后对应库存减少1个
tempApples[1]--;
count++;
break;
}
}
}
return count;
}
}
划重点!!
1. Queue/PriorityQueue
2. Comparator