239. 滑动窗口最大值:
题目链接
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 :
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
解答:
class MyQueue {
Deque<Integer> deque = new LinkedList<>();
void poll(int val) {
if (!deque.isEmpty() && val == deque.peek()) {
deque.poll();
}
}
void add(int val) {
while (!deque.isEmpty() && val > deque.getLast()) {
deque.removeLast();
}
deque.add(val);
}
//队列队顶元素始终为最大值
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[] res = new int[len];
int num = 0;
//自定义队列
MyQueue myQueue = new MyQueue();
//先将前k的元素放入队列
for (int i = 0; i < k; i++) {
myQueue.add(nums[i]);
}
res[num++] = myQueue.peek();
for (int i = k; i < nums.length; i++) {
//滑动窗口移除最前面的元素,移除是判断该元素是否放入队列
myQueue.poll(nums[i - k]);
//滑动窗口加入最后面的元素
myQueue.add(nums[i]);
//记录对应的最大值
res[num++] = myQueue.peek();
}
return res;
}
}
算法总结:
本题我们创建一个新的队列,他的判断法则是保证本次递归在队列头部的一定是当前最大的数字,如果尾部出现不是不如当前入队的大的数字则将他出队,并在下一次窗口滑动时将头部出队(如果头部已经不是当前窗口)
347. 前 K 个高频元素:
题目链接
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 :
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
解答:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
int[] res = new int[k];
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums) map.put(num, map.getOrDefault(num, 0) + 1);
for(var x : map.entrySet()) {
int[] tmp = new int[2];
tmp[0] = x.getKey();
tmp[1] = x.getValue();
pq.offer(tmp);
if(pq.size() > k) {
pq.poll();
}
}
for(int i = 0; i < k; i ++) {
res[i] = pq.poll()[0];
}
return res;
}
}
算法总结:
本题提到k个高频元素,我们第一个想到的是用map记录元素的频率,key是元素本身,value存储次数,其次又要求前k个高频元素,我们可以用优先级队列对队列本身进行一个排序,当队列内元素数量大于k时弹出队头元素,最后结果为所求数组。