239. 滑动窗口最大值
自动创建一个单调队列,用java的双端队列deque为基底:
- 首先明确结果数组的大小为 i - k + 1个。
- 先把前k个数都压入队列;
- 然后遍历n - k个数,不断滑动,nums[i]入队,nums[i - k]出队;
class Solution {
public class MonotonicQueue{
private Deque<Integer> deque = new LinkedList<>();
public void push(int n){
// 将小于n的元素全部移除
while (!deque.isEmpty() && deque.getLast() < n) {
deque.removeLast();
}
// 将n添加到队列中
deque.addLast(n);
}
public int max() {
// 队首元素就是最大的元素
return deque.getFirst();
}
public void pop(int n) {
// 如果n等于队首元素,那么移除它
if (n == deque.getFirst()) {
deque.removeFirst();
}
}
}
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res = new int[nums.length - k + 1];//结果的个数;
int index = 0;//用于给res计数
MonotonicQueue queue = new MonotonicQueue();
for(int i = 0; i < k; i++){
queue.push(nums[i]);
}
res[index++] = queue.max();
for (int i = k; i < nums.length; i++) {
queue.push(nums[i]);
queue.pop(nums[i - k]);
res[index++] = queue.max();
}
return res;
}
}
347. 前K个高频元素
这题用的是优先级队列,也就是大根堆。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for (int num : nums) {
map.merge(num, 1, Integer::sum);
}
//创建优先队列
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(
(n1, n2) -> map.get(n1).equals(map.get(n2)) ?
n2.compareTo(n1) : map.get(n1) - map.get(n2)
);
for(int n: map.keySet()){
priorityQueue.add(n);
if(priorityQueue.size() > k){
priorityQueue.poll();
}
}
int[] result = new int[priorityQueue.size()];
int i = 0;
while (!priorityQueue.isEmpty()) {
result[i++] = priorityQueue.poll();
}
return result;
}
}
- map.merge(num, 1, Integer::sum); java8加入的语法,意思是说如果num不存在就创建减值对,value为1,存在就在原来的value上+1,相当于:
if (map.containsKey(num)) { // 如果map中已经包含了这个数字,那么将这个数字的频率加1
map.put(num, map.get(num) + 1);
} else { // 如果map中还没有这个数字,那么将这个数字的频率设置为1
map.put(num, 1);
}
- PriorityQueue priorityQueue = new PriorityQueue<>( (n1, n2) -> map.get(n1).equals(map.get(n2)) ? n2.compareTo(n1) : map.get(n1) - map.get(n2) );
是一个lambda表达式,自定义了一个比较器,意思是插入队列的依然是键,但大小是根据值比较。
- add入队poll出队;