代码随想录算法训练营第十三天| 239.滑动窗口最大值(双端队列登场),347.前k个高频元素(优先级队列)

 239.滑动窗口最大值(双端队列登场)

239. 滑动窗口最大值

 第一次接触双端队列,思考了很久,理解了很久

对于例子“1,3,-1,-3,5,3,6,7”  k=3

我们自定义一个单调递减队列来保证队首的元素是队列中最大的,单调队列采用dqeue来构造,里面方法的规则不同题目有不同要求

1.首先将前k个元素入队,入队的规则是,如果队首元素小于当前要入队的元素,那么要先将所有小于当前元素的队列元素弹出,再用add()方法将当前元素加入到队尾

2.前k个元素入过队后,滑动窗口每向后移动一个元素,就要移除最前面的元素,所以要判断一下队首元素是否等于滑动窗口最前面的元素(注意:肯定不是判断队尾元素,而是判断队首元素)

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;
        //自定义队列
        MyDeque myDeque=new MyDeque();
        //需要先将前k个元素放入队列
        for(int i=0;i deque=new LinkedList<>();
     //
     void poll(int val){
         //滑动窗口移除最前面的元素,移除时要判断该元素是否被放入队列,因为可能在形成该滑动窗口的单调队列的时候,因为这个元素比较小,所以很早就被pop出去了,那样的化就不存在移除的说法了
         if(!deque.isEmpty()&&val==deque.peek()){//判断要移除的元素和队首元素是否相等
            deque.poll();//移除队首元素

         }

     }
     void add(int val){
         //添加时要判断,如果队首元素小于当前要入队的元素,那么应该把小于当前要入队的元素全部pop出去,保持队列的单调性
          while(!deque.isEmpty()&&deque.getLast()

什么是优先级队列呢?

其实就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。

347.前k个高频元素

347. 前 K 个高频元素

什么是堆呢?

堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。

所以大家经常说的大顶堆(堆头是最大元素),小顶堆(堆头是最小元素),如果懒得自己实现的话,就直接用priority_queue(优先级队列)就可以了,底层实现都是一样的,从小到大排就是小顶堆,从大到小排就是大顶堆。

遍历Map的方式: Map.Entry 和 Map.entrySet(),Map.Entry里有相应的getKey和getValue方法,让我们能够从一个项中取出Key和Value

思路:首先用HashMap统计出现频率,

其次优先队列在这里是按照出现频次作为优先依据,优先队列中存储二元组(num,count),如果队列中的元素小于k个,那么直接添加就可以,否则就需要判断小顶堆的根节点(最小)的频次是否小于当前要加入的元素的频次,是则替换之,

最后堆ans数组倒序赋值输出结果

注意点

优先队列在这里基于小顶堆实现(只能从队头移出元素,从队尾添加元素)

同时注意这里是用Map.Entry遍历map的!

实现代码

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map map=new HashMap();
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);

        }
        //优先级队列,基于小顶堆实现(队头->队尾,小->大)
        //在优先队列中存储二元组(num,cnt),cnt表示元素值num在数组中的出现次数
        PriorityQueue pq=new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
        for(Map.Entry entry:map.entrySet()){//利用Map.Entry的方式遍历map
            if(pq.size()pq.peek()[1]){//没见过这个用法其实
                   pq.poll();//弹出队头
                   pq.add(new int[]{entry.getKey(),entry.getValue()});
                    
                }
            }
        }
        //输出前k个 
        int[] ans=new int[k];
        for(int i=k-1;i>=0;i--){
            ans[i]=pq.poll()[0];//倒序存放,方便出现次数小的先放

        }
        return ans;

    }

}

你可能感兴趣的:(算法,数据结构,leetcode)