赞
踩
目录
比较难,了解思路就可以,二刷的时候再看
- //解法一
- //自定义数组
- class MyQueue {
- Deque<Integer> deque = new LinkedList<>();
- //弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出
- //同时判断队列当前是否为空
- void poll(int val) {
- if (!deque.isEmpty() && val == deque.peek()) {
- deque.poll();
- }
- }
- //添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出
- //保证队列元素单调递减
- //比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2
- 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;
- }
- }
-
- //解法二
- //利用双端队列手动实现单调队列
- /**
- * 用一个单调队列来存储对应的下标,每当窗口滑动的时候,直接取队列的头部指针对应的值放入结果集即可
- * 单调队列类似 (tail -->) 3 --> 2 --> 1 --> 0 (--> head) (右边为头结点,元素存的是下标)
- */
- class Solution {
- public int[] maxSlidingWindow(int[] nums, int k) {
- ArrayDeque<Integer> deque = new ArrayDeque<>();
- int n = nums.length;
- int[] res = new int[n - k + 1];
- int idx = 0;
- for(int i = 0; i < n; i++) {
- // 根据题意,i为nums下标,是要在[i - k + 1, i] 中选到最大值,只需要保证两点
- // 1.队列头结点需要在[i - k + 1, i]范围内,不符合则要弹出
- while(!deque.isEmpty() && deque.peek() < i - k + 1){
- deque.poll();
- }
- // 2.既然是单调,就要保证每次放进去的数字要比末尾的都大,否则也弹出
- while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
- deque.pollLast();
- }
-
- deque.offer(i);
-
- // 因为单调,当i增长到符合第一个k范围的时候,每滑动一步都将队列头节点放入结果就行了
- if(i >= k - 1){
- res[idx++] = nums[deque.peek()];
- }
- }
- return res;
- }
- }
哈希表的getOrDefault(key, default)方法,是在哈希表中搜索是否存在该方法参数列表中的key值,如果存在该key值,则返回哈希表中该key值对应的vakue值;如果不存在,则返回该方法参数列表中的default值。
大根堆
(pair1, pair2)->pair2[1]-pair1[1]
小根堆
(pair1,pair2)->pair1[1]-pair2[1]
Map是java中的接口,Map.Entry是Map的一个内部接口。
Map提供了一些常用方法,如keySet()、entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。
- 基于小顶堆实现
- public int[] topKFrequent2(int[] nums, int k) {
- Map<Integer,Integer> map = new HashMap<>();//key为数组元素值,val为对应出现次数
- for(int num:nums){
- map.put(num,map.getOrDefault(num,0)+1);
- }
- //在优先队列中存储二元组(num,cnt),cnt表示元素值num在数组中的出现次数
- //出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头(相当于小顶堆)
- PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
- for(Map.Entry<Integer,Integer> entry:map.entrySet()){//小顶堆只需要维持k个元素有序
- if(pq.size()<k){//小顶堆元素个数小于k个时直接加
- pq.add(new int[]{entry.getKey(),entry.getValue()});
- }else{
- if(entry.getValue()>pq.peek()[1]){//当前元素出现次数大于小顶堆的根结点(这k个元素中出现次数最少的那个)
- pq.poll();//弹出队头(小顶堆的根结点),即把堆里出现次数最少的那个删除,留下的就是出现次数多的了
- pq.add(new int[]{entry.getKey(),entry.getValue()});
- }
- }
- }
- int[] ans = new int[k];
- for(int i=k-1;i>=0;i--){//依次弹出小顶堆,先弹出的是堆的根,出现次数少,后面弹出的出现次数多
- ans[i] = pq.poll()[0];
- }
- return ans;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。