leetcode:吃苹果和队列

一、最小堆(PriorityQueue)基础操作

1. 核心作用

  • 自动排序,堆顶永远是最小元素(最小堆)

  • 适用场景:优先处理 "最早过期""最小" 等优先级问题(如吃苹果)

2. 必背 4 个核心方法

方法 作用 备注
add(x) 向堆中添加元素 与 offer(x) 功能完全一致,写题随便用
offer(x) 向堆中添加元素 同上
peek() 查看堆顶元素(不删除) 用于 "判断堆顶是否符合条件"(如苹果是否过期)
poll() 取出堆顶元素(并删除) 用于 "移除堆顶"(如扔掉烂苹果、吃苹果)

3. 最小堆创建语法

复制代码
// 堆中存 int[](如 {过期天数, 苹果数量}),按数组第 0 位升序排序(小的在前)PriorityQueue<int[]> minHeap = new PriorityQueue b) -> a[0] - b[0]);

4. 记忆口诀

复制代码
add/offer 放进去,peek 看一眼,poll 拿走它小减大 → 最小堆(a[0]-b[0])

二、题目 1:吃苹果(eatenApples)

1. 核心思想

每天按 "加新苹果 → 扔烂苹果 → 吃最快烂的苹果" 三步执行,用最小堆维护优先级。

2. 解题步骤(模板)

java 复制代码
PriorityQueue[]> heap = new PriorityQueue<>((a, b) -> a[0] - b[0]);

int day = 0, res = 0;

while (day !heap.isEmpty()) {

// 1. 加当天新苹果(如果还有苹果没长出来)

if (day < apples.length && apples[day] > 0) {

int expireDay = day + days[day]; // 过期时间 = 当前天 + 保质期

heap.offer(new int[]{expireDay, apples[day]});

}

// 2. 扔烂苹果(堆顶过期 ≤ 当前天 → 移除)

while (!heap.isEmpty() && heap.peek()[0] day) {

heap.poll();

}

// 3. 吃苹果(堆不为空则吃1个)

if (!heap.isEmpty()) {

int[] curr = heap.poll();

res++; // 吃1个,计数+1

curr[1]--; // 剩余苹果数-1

if (curr[1] > 0) { // 没吃完的放回堆

heap.offer(curr);

}

}

day++;

}

return res;

3. 关键注意点

  • 先清烂苹果,再吃苹果(避免吃烂的)

  • 苹果没吃完要重新放回堆(offer(curr))

  • 循环条件:day < 苹果数组长度 || 堆不为空(苹果长完了但堆里还有没吃完的)


二、题目 2:设计循环队列(MyCircularQueue)

1. 核心思想

  • 用数组模拟 "头尾绕圈" 的队列,遵循 先进先出(FIFO)

  • 用 count 计数(最稳,避免 "牺牲一个位置" 的容量问题)

2. 成员变量(4 个)

java 复制代码
private int[] data;   
 // 存数据的数组
 private int front;     
 // 队头(指向第一个元素)
 private int rear;      
 // 队尾(指向"下一个空位")private int maxSize;   
 // 队列最大容量
 private int count;     
 // 当前元素个数(判断空/满的核心)

3. 7 个方法(完整模板)

(1)构造方法
java 复制代码
public MyCircularQueue(int k) {    
maxSize = k;    
data = new int[k];    
front = 0;    
rear = 0;    
count = 0;
}
(2)入队(enQueue)
java 复制代码
public boolean enQueue(int value) {    
if (isFull()) return false; 
// 满了不能入队    
data[rear] = value;         
// 放在队尾空位    
rear = (rear + 1) % maxSize; 
// 队尾绕圈后移    
count++;                    
// 元素个数+1    return true;}
(3)出队(deQueue)
java 复制代码
public boolean deQueue() {    
if (isEmpty()) return false; 
// 空了不能出队    
front = (front + 1) % maxSize; 
// 队头绕圈后移(相当于删除)    
count--;                      
// 元素个数-1    
return true;
}
(4)取队头(Front)
java 复制代码
public int Front() {    
if (isEmpty()) return -1;    
return data[front]; 
// front 直接指向队头元素
}
(5)取队尾(Rear)→ 最容易错
java 复制代码
public int Rear() {    
if (isEmpty()) return -1;    
// rear 是下一个空位,真正队尾是 rear 前一位(绕圈避免负数)    
int lastIndex = (rear - 1 + maxSize) % maxSize;    
return data[lastIndex];
}
(6)判断为空(isEmpty)
java 复制代码
public boolean isEmpty() {    
return count == 0; 
// count 为 0 则空
}
(7)判断为满(isFull)
java 复制代码
public boolean isFull() {    
return count == maxSize; 
// count 等于最大容量则满}

4. 关键注意点

  • 循环下标:永远用 (i + 1) % maxSize(避免越界,实现绕圈)

  • 队尾计算:(rear - 1 + maxSize) % maxSize(防止 rear=0 时出现负数下标)

  • 优先用 count 判断空 / 满(比 "牺牲一个位置" 更直观,不易错)


三、常见踩坑总结

1. 最小堆

  • 混淆 add/offer:两者功能一致,无需纠结

  • 忘记 peek() 不删除、poll() 会删除:导致逻辑漏判或误删

2. 循环队列

  • 把 rear 当成队尾元素:实际是 "下一个空位",取队尾需 -1

  • 成员变量写漏 / 位置错:导致 cannot find symbol 报错

  • 类内部调用方法加对象名:如 this.isEmpty() 可直接写 isEmpty()

3. 通用避坑规则

  1. 队列永远 "尾进头出"

  2. 循环结构下标必用 % 容量

  3. 不确定空 / 满时,用 count 计数(最稳)

  4. 写题先判断边界(空 / 满 / 越界),再执行核心逻辑

相关推荐
梦梦代码精22 分钟前
为什么这个开源的AI平台会火?有点东西。。。
人工智能·算法·机器学习·docker·开源
随意起个昵称42 分钟前
线性dp-综合刷题1(Not Alone)
算法·动态规划
如何原谅奋力过但无声2 小时前
【灵神高频面试题合集09-13】二叉树、二叉搜索树
数据结构·算法·leetcode
皆圥忈2 小时前
磁盘物理结构与文件系统基础讲解
linux·算法
数据仓库搬砖人2 小时前
用 LangGraph 从零搭一个客服 Agent:多轮对话 + 工具调用全流程
算法
GuWenyue2 小时前
告别JS类型坑!Ts为什么在ai时代逐渐成为"第一"语言
前端·算法·typescript
子琦啊2 小时前
哈希与前缀和
算法·哈希算法
Deep-w2 小时前
【MATLAB】基于离散 LQR 的车辆横向轨迹跟踪控制方法研究
开发语言·算法·matlab
Peter·Pan爱编程2 小时前
23. 算法库:用算法代替手写循环
c++·人工智能·算法
小欣加油3 小时前
leetcode2161 根据给定数字划分数组
数据结构·c++·算法·leetcode·职场和发展