栈与队列的应用
239.滑动窗口的最大值
- 使用单调队列模拟滑动窗口, 始终保证窗口内元素个数为k个, 且元素为单调递减
- 当遍历到k之后, 每次处理一个元素就从队列头出队一个元素, 即为该区间的最大值
代码:
class Solution {
// 固定滑动窗口大小---求滑动窗口的最大值, 最小值, 中位数
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
int[] ans = new int[n-k+1];
// 单调队列---单调递减队列
// 队列中装的是数组元素下标
int idx = 0;
Deque<Integer> deque = new ArrayDeque<>();
for(int i=0; i < nums.length; i++){
// 1.维护队列内部元素的个数 <= k, 队列头元素下标<i-k+1
while(!deque.isEmpty() && deque.peekFirst() < i-k+1){
deque.pollFirst();
}
// 2.保证单调递减
while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]){
deque.pollLast();
}
// 3.存入元素
deque.offerLast(i);
if(i >= k-1) ans[idx++] = nums[deque.peekFirst()];
}
return ans;
}
}
347.前k个高频元素
基于小顶堆实现:
- 先用哈希表统计每个元素的数量
- 构造k个元素的小顶堆
- 遍历哈希表, 若索引小于k, 直接入队
- 当索引大于k, 判断其与堆顶元素大小, 若比堆顶元素大, 则入队; 比堆顶元素还小, 则不入队
- 最后遍历完成, 小顶堆内剩下的就是前k个最高频的元素
代码:
class Solution {
// 基于小顶堆: 时间复杂度 O(nlogk)
public int[] topKFrequent(int[] nums, int k) {
int[] ans = new int[k];
// 1.用哈希表统计元素个数
HashMap<Integer, Integer> map = new HashMap<>();
for(int i=0; i<nums.length; i++){
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
// 2.构造一个 k 个元素的小顶堆---默认就是小顶堆
PriorityQueue<int[]> queue = new PriorityQueue<>((c1,c2)->c1[1]-c2[1]);
int index = 0;
for(int num : map.keySet()){
if(index++ < k) {
queue.offer(new int[]{num, map.get(num)});
}else{
if(map.get(num) > queue.peek()[1]){
queue.poll();
queue.offer(new int[]{num, map.get(num)});
}
}
}
// 3. 输出答案
for(int i=0; i<k; i++){
ans[i] = queue.poll()[0];
}
return ans;
}
}