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
本题运用单调队列
单调队列:单调递减或单调递增的队列
设计单调队列的时候,pop,和push操作要保持如下规则:
- pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
- push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。
解题思路:
- 定义一个队列deque(用来存储对应的下标)
- 下标的范围应该是[i-k+1,i],所以需要满足的第一个条件就是
deque.peek()<i-k+1
- 因为是一个单调队列,所以如果存入的数字比末尾的大,需要被弹出
nums[deque.peekLast()]<nums[i]
- 每当i符合一个k的范围,将
deque.peek()
存入到结果当中
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
ArrayDeque<Integer> deque=new ArrayDeque<>();
int[] reslut=new int[nums.length-k+1];
int index=0;
for(int i=0;i<nums.length;i++){
while(!deque.isEmpty()&&deque.peek()<i-k+1){
deque.poll();
}
while(!deque.isEmpty()&&nums[deque.peekLast()]<nums[i]){
deque.pollLast();
}
deque.offer(i);
if(i>=k-1){
reslut[index++]=nums[deque.peek()];
}
}
return reslut;
}
}
Java中由ArrayDeque实现的接口
用Java创建ArrayDeque双端队列的方法:ArrayDeque<Type> animal = new ArrayDeque<>();
ArrayDeque方法:
- 使用add(),addFirst()和addLast()添加元素
- 使用 offer(),offerFirst()和offerLast()插入元素
- 使用getFirst()和getLast()访问元素
- 使用peek(),peekFirst()和peekLast()方法访问元素
- 使用remove(),removeFirst(),removeLast()方法删除元素
- 使用poll(),pollFirst()和pollLast()方法删除元素
347. 前 K 个高频元素
给你一个整数数组
nums
和一个整数k
,请你返回其中出现频率前k
高的元素。你可以按 任意顺序返回答案。
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
该题使用优先队列
Java PriorityQueue类是一种队列数据结构实现,其中根据优先级处理对象。 默认情况下,优先级队列的对象按自然顺序排序。
解题思路:
- 定义一个Map,其中Map键位num的值,值为num出现的次数
- 定义一个优先队列,将队列转换为Set集合,并将值和出现的次数添加到优先队列中,并且元素要按照从大到小排序
- 定义一个需要返回的数组,遍历弹出pq的值
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map=new HashMap<>();
//定义Map键位num的值,值为num出现的次数。
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
//定义一个优先队列
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2)->pair2[1]-pair1[1]);
for(Map.Entry<Integer,Integer> entry:map.entrySet()){//大顶堆需要对所有元素进行排序
pq.add(new int[]{entry.getKey(),entry.getValue()});
}
int[] reslut=new int[k];
for(int i=0;i<k;i++){
reslut[i]=pq.poll()[0];
}
return reslut;
}
}
Java HashMap getOrDefault() 方法
getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。
getOrDefault() 方法的语法为:hashmap.getOrDefault(Object key, V defaultValue)
Java HashMap entrySet() 方法
entrySet() 方法返回映射中包含的映射的 Set 视图。
entrySet() 方法的语法为:hashmap.entrySet()
Lambda表达式 --> 函数式编程(函数编程思想)
-
标准格式:(参数列表) -> {代码}
-
格式说明:
小括内的语法与传统方法参数列表一致,没有参数就留空,有多个参数就用逗号分隔
【->】 是新引入的语法格式,代表指向动作
大括号内的语法与传统方法体要求一致
-
比较器案例
List<Integer> list = new ArrayList<>(); Collections.addAll(list,11,22,33,44,55); System.out.println("排序之前的集合:" + list); // 比较器的正常书写格式 Collections.sort(list, new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2-o1; } }); // Lambda表达式 Collections.sort(list,(Integer o1, Integer o2)->{return o2-o1;}); System.out.println("排序之后的集合:" + list);