Leetcode 239. 滑动窗口最大值
题目链接
思路:自定义单调队列,入队的时候判断该元素是否大于队头元素,如果大于,则将对头元素弹出,然后入队,以保证队头元素是最大值,出队的时候就是判断要出队的元素是否入队了,如果没有不等于队头元素,也就是说明出队的元素压根儿就没有入队,直到要出队的元素等于队头元素的时,说明找到了最大的元素,出队。
代码:
class MyQueue {
Deque<Integer> deque = new LinkedList<>();
// 添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出
// 保证队列元素单调递减
// 比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2
void add(int val) {
while (!deque.isEmpty() && val > deque.getLast()) {
deque.removeLast();
}
deque.add(val);
}
// 弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出
// 这里想等才弹出是因为比队列出口小的元素在push的时候就已经被弹出了
// 同时判断队列当前是否为空
void poll(int val) {
if (!deque.isEmpty() && val == deque.peek()) {
deque.poll();
}
}
// 队列队顶元素始终为最大值
int peek() {
return deque.peek();
}
}
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 1) {
return nums;
}
int len = nums.length - k + 1;
int[] result = new int[len];
int num = 0;
// 自定义队列
MyQueue myQueue = new MyQueue();
// 将前k的元素放入队列
for (int i = 0; i < k; i++) {
myQueue.add(nums[i]);
}
// 将第一个滑动窗口的最大值加入result
result[num++] = myQueue.peek();
for (int i = k; i < nums.length; i++) {
//滑动窗口移除最前面的元素,也就是判断该元素是否放入队列
myQueue.poll(nums[i - k]);
//滑动窗口加入最后面的元素
myQueue.add(nums[i]);
//记录对应的最大值
result[num++] = myQueue.peek();
}
return result;
}
}
Leetcode 347.前 K 个高频元素
题目链接
思路:使用小顶堆特性,根节点小,子节点大,直接上代码,简单明了
代码:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
int[] res = new int[k];
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
// 使用小顶堆,根据map的value值正序排序,创建优先级队列
PriorityQueue<Map.Entry<Integer, Integer>> queue =
new PriorityQueue<>(Map.Entry.comparingByValue());
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
queue.offer(entry);
// 弹出较小的根节点
if (queue.size() > k) {
queue.poll();
}
}
// 将小顶堆下面较大的元素依次加入res数组
for (int i = k - 1; i >= 0; i--) {
res[i] = Objects.requireNonNull(queue.poll()).getKey();
}
return res;
}
}