leetcode 刷题_day13_栈和队列03_单调队列&小顶堆

239. 滑动窗口最大值

思路

构建一个适用于本题的单调递减非去重队列

  1. 从队尾执行 push 操作时,从队尾开始,所有小于当前元素的都会被出队列 --> 保证队列内所有元素单调递减
  2. 从对头执行 pop 操作时,判断队头元素是否等于当前元素,等于就出队列,不等于则不执行 --> 对于单调递减队列,队头就是最大元素,不能随意出队列,除非要出的就是最大数值;且本题中只要求最大值,不要求其他的数值。

注意,单调递减队列不能去重,否则会导致移除元素时误将窗口还在的数据被移除出去

解题思路

复杂度

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( k ) ) O(k)) O(k))

代码

Java

// 单调递减非去重队列
class MyDeque {
    Deque<Integer> deque = new LinkedList<Integer>();

    void push(int val) {
        
        while(!deque.isEmpty() && deque.getLast() < val) {
            deque.removeLast();
        }

        deque.addLast(val);
    }

    void pop(int val) {
        if(!deque.isEmpty() && deque.peek() == val) {
            deque.removeFirst();
        }
    }

    int getMax() {
        return deque.peek();
    }
}

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
      // 构建滑动窗口
      int len = nums.length - k + 1;
      int[] result = new int[len];
      int resIndex = 0;
      // 构建单调递减队列
      MyDeque myDeque = new MyDeque();

      // 首先将初始窗口放到队列中
      for(int i = 0; i < k; i++) {
          myDeque.push(nums[i]);
      }
      result[resIndex++] = myDeque.getMax();

      // 窗口遍历数组,队列 push 窗口新增元素,pop 窗口移除元素
      for (int i = k; i < nums.length; i++) {
          myDeque.pop(nums[i - k]);
          myDeque.push(nums[i]);
          result[resIndex++] = myDeque.getMax();
      }

      return result;
    }
}

347.前 K 个高频元素

思路

  1. 通过哈希表(基于map实现)统计数组各个元素的出现次数
  2. 通过小顶堆(出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头)获取前 k 个高频元素
  3. 优先队列存储二元组(数组模拟),存储时,如果当前元素的频次大于堆顶且优先队列内长度大于等于 k,则队头 poll,始终保持队列长度小于等于 k

解题思路

复杂度

时间复杂度: O ( n l o g k ) O(nlogk) O(nlogk)

空间复杂度: O ( n ) O(n) O(n)

代码

Java

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        // 通过哈希表(基于map实现)统计数组各个元素的出现次数
        Map<Integer, Integer> map = new HashMap<>();
        for(int num: nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }

        // 通过小堆顶(出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头)获取前 k 个高频元素
        // 优先队列存储二元组(数组模拟),存储时,如果当前元素的频次大于堆顶且优先队列内长度大于等于 k,则队头 poll,始终保持队列长度小于等于 k
        // 这样队列内就是前 k 个高频元素
        PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair1[1] - pair2[1]);
        for(Map.Entry<Integer, Integer> entry: map.entrySet()) {
            if (pq.size() < k) {
                pq.add(new int[]{entry.getKey(), entry.getValue()});
            } else if (entry.getValue() > pq.peek()[1]) {
                pq.poll();
                pq.add(new int[]{entry.getKey(), entry.getValue()});
            }
        }

        int[] result = new int[k];
        for(int i = 0; i < k; i++) {
            result[i] = pq.poll()[0];
        }

        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值