LeeCode 栈与队列问题(二)
LeeCode 239: 滑动窗口最大值
题目描述
给你一个整数数组
nums
,有一个大小为k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
建立模型
- 单调队列:保存还未被删除的下标, 下标对应的值单调递减
- 对于前
k
个数,下标\(0 \le i < j < k\),若 \(nums[i] \ge nums[j]\),则 nums[i]永远不会成为最大值,无需保存 - 对于 [k, nums.length() - 1],循环比较队尾元素和当前元素的大小关系,若当前元素大于等于队尾元素则说明队尾元素永远不会成为最大值,无需保存;
- 然后插入当前元素下标
代码实现
# Python3 实现
def MaxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
# 特殊情况
if k >= len(nums):
return max(nums)
# 使用双端队列保存下标
queue = collections.deque()
# 前 k 个元素
for i in range(k):
while queue and nums[queue[-1]] <= nums[i]:
queue.pop()
queue.append(i)
res = [nums[queue[0]]]
for i in range(k, len(nums)):
while queue and nums[queue[-1]] <= nums[i]:
queue.pop()
queue.append(i)
while queue[0] <= i - k:
queue.popleft()
res.append(nums[queue[0]])
return res
// Java 实现
public int[] maxSlidingWindow(int[] nums, int k) {
if (k >= nums.length) {
// return max(nums);
}
Deque<Integer> deque = new ArrayDeque<>();
for (int i = 0; i < k; i++) {
while(!deque.isEmpty() && nums[deque.getLast()] <= nums[i]) {
deque.removeLast();
}
deque.add(i);
}
int[] res = new int[nums.length - k + 1];
res[0] = nums[deque.getFirst()];
int index = 1;
for (int i = k; i < nums.length; i++) {
while(!deque.isEmpty() && nums[deque.getLast()] <= nums[i]) {
deque.removeLast();
}
deque.add(i);
while (deque.getFirst() <= i - k) {
deque.removeFirst();
}
res[index++] = nums[deque.getFirst()];
}
return res;
}
LeeCode 347: 前 K 个高频元素
题目描述
给你一个整数数组
nums
和一个整数k
,请你返回其中出现频率前k
高的元素。你可以按任意顺序返回答案。
建立模型
这是一个堆的问题,这类问题还有比如前K个高频单词,最小K个数等。
- 遍历数组统计所有出现的数字和频数
- 建立一个存储K个元素的小顶堆(自定义排序规则),每次比较堆顶元素和当前元素
- 若当前元素频数大于堆顶元素,则将堆顶元素弹出,添加当前元素
- 返回堆中的所有元素
代码实现
// Java 实现
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
/**
* 自定义排序规则
* 按照数组第2个元素值从小到大排序
*/
Comparator<int[]> comparator = new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
// TODO Auto-generated method stub
return o1[1] - o2[1];
}
};
// 小顶堆的实现
PriorityQueue<int[]> queue = new PriorityQueue<>(comparator);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int num = entry.getKey();
int value = entry.getValue();
if (queue.size() < k) {
queue.offer(new int[]{num, value});
}
else {
if (queue.peek()[1] < value) {
queue.poll();
queue.offer(new int[]{num, value});
}
}
}
int[] res = new int[k];
int index = 0;
while (index < k) {
res[index++] = queue.poll()[0];
}
return res;
}