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. 写题先判断边界(空 / 满 / 越界),再执行核心逻辑

相关推荐
多恩Stone1 小时前
【3D-AICG 系列-15】Trellis 2 的 O-voxel Shape: Flexible Dual Grid 代码与论文对应
人工智能·python·算法·3d·aigc
weixin_448119941 小时前
Datawhale 大模型算法全栈基础篇 202602第4次笔记
笔记·算法
sali-tec1 小时前
C# 基于OpenCv的视觉工作流-章27-图像分割
图像处理·人工智能·opencv·算法·计算机视觉
踩坑记录2 小时前
leetcode hot100 74. 搜索二维矩阵 二分查找 medium
leetcode
TracyCoder1232 小时前
LeetCode Hot100(60/100)——55. 跳跃游戏
算法·leetcode
月挽清风2 小时前
代码随想录第35天:动态规划
算法·动态规划
岛雨QA2 小时前
链表「Java数据结构与算法学习笔记3」
数据结构·算法
Sunsets_Red2 小时前
P8277 [USACO22OPEN] Up Down Subsequence P 题解
c语言·c++·算法·c#·学习方法·洛谷·信息学竞赛
汉克老师2 小时前
GESP2023年12月认证C++二级( 第三部分编程题(2) 小杨的H字矩阵)
c++·算法·矩阵·循环结构·gesp二级·gesp2级