给你一个整数数组
nums
,有一个大小为k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k
个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。
本题一开始我使用的暴力解法,窗口里的值一发生变化就遍历一次窗口找最大值。提交后超时了,看了下超时的数据,窗口长度有1000多,遂思考解决办法。
窗口里其实我们只关心最大值,以及最大值出队之后下一个值是什么。我们构想一个数据结构,基于队列,队首至队尾从大到小排列,这样能保证队首一直是窗口里的最大值。基于这个构想,我们思考插入规则。
插入规则:当数A进入窗口队列时,窗口队列中比A小的数其实就没有意义了,因为A既大于他们,又比他们后从窗口队列中出队,最大值不可能取到这些比A小的值,所以,A入队时,直接将比A小的数全部从队尾出队。这样就保证了队列从大到小的顺序。现在我们再来思考窗口队列的出队规则。
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
LinkedList<Integer> queue = new LinkedList<>();
LinkedList<Integer> indexs = new LinkedList<>();
int [] result = new int[nums.length - k + 1];
int resultIndex = 0;
int maxMark;
for (int i = 0; i < nums.length; i++) {
while (!queue.isEmpty() && queue.peekLast() < nums[i]){
queue.removeLast();
indexs.removeLast();
}
queue.addLast(nums[i]);
indexs.addLast(i);
if(i - indexs.getFirst() >= k){
queue.removeFirst();
indexs.removeFirst();
}
if (i >= k-1){
maxMark = queue.getFirst();
result[resultIndex++] = maxMark;
}
}
return result;
}
}
代码有优化空间,没必要用两个队列,用一个队列只存储index就行了,index即包含了位置信息,也包含了具体的值。
347.前 K 个高频元素
给你一个整数数组
nums
和一个整数k
,请你返回其中出现频率前k
高的元素。你可以按 任意顺序 返回答案。示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]示例 2:
输入: nums = [1], k = 1 输出: [1]
这题没什么好说的,首先遍历原数组,统计次数,然后再在其中找出最大的K个数。难处理的点主要在于找出最大的前K个数。
比较容易想到的方法有:
1、排序取前K个数
2、构建大顶堆
偷懒用队列排了,也通过了
public class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int a:nums
) {
if (!map.containsKey(a)) map.put(a, 1);
else {
map.put(a, map.get(a) + 1);
}
}
LinkedList<Integer> queue = new LinkedList<>();
LinkedList<Integer> back = new LinkedList<>();
for (int a:map.keySet()
) {
while (!queue.isEmpty() && map.get(queue.peekLast()) <= map.get(a)){
int rm = queue.removeLast();
back.addLast(rm);
}
if(queue.size() < k) queue.addLast(a);
while (!back.isEmpty() && queue.size() != k){
int rm = back.removeLast();
queue.addLast(rm);
}
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = queue.removeLast();
}
return result;
}
}