代码随想录算法训练营第十二天 | LeetCode 239. 滑动窗口最大值、LeetCode 347. 前 K 个高频元素

简介: 代码随想录算法训练营第十二天 | LeetCode 239. 滑动窗口最大值、LeetCode 347. 前 K 个高频元素

代码随想录算法训练营第十二天 | LeetCode 239. 滑动窗口最大值、LeetCode 347. 前 K 个高频元素

文章链接:代码随想录滑动窗口最大值        代码随想录前K个高频元素

视频链接:代码随想录滑动窗口最大值        代码随想录前K个高频元素

1. LeetCode 239. 滑动窗口最大值

1.1 思路

  1. 题目的意思有点类似一个队长为k的队列里求最大值,每次队列往后移一位,每次都求最大值,因此可以实现一个单调队列,poll()方法每次移动的时候就抛弃不要的元素,add()方法每次移动的时候就添加队尾新元素,peek()方法每次移动完就求最大值,这个数据结构需要自己实现,我们管这个叫单调队列
  2. 由于是自定义的数据结构,所以不用每次都把k个元素放入队列中,只需要维护队首即为最大值即可,下面以“1,3,-1,-3,5,3,2,1”举例
  3. poll()方法就是遗弃不需要的元素,add()方法就是添加新的元素,peek()就是求最大值弹出队首
  4. 最开始1先add()进来,然后3add()进来,这时判断如果队尾有元素比3大就弹出,直到没有比3大的为止,意思就是左边的元素如果比新加入的元素小就可以全部弹出(又老又小),add()进来的元素比前面都大前面的元素就都要排除
  5. poll()方法则是如果要移除的元素正是队首元素(最大值),则弹出,否则不用操作
  6. 注意此题中我们自己实现的时候,其实很多弹出操作在add()方法里就实现了。并且注意,删除的时候(不管是add还是poll方法)要在前面加条件 !deque.isEmpty() 判断队列不为空,不然就对空队列操作了

1.2 代码

//自定义数组
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;
    }
}

2. LeetCode 347. 前 K 个高频元素

2.1 思路

  1. 难点1:如何求对应元素的出现频率。难点2:如何把频率排序,并求前k个
  2. 对于难点1,可以用map数据结构,因为是key-value,key存放对应的元素,value就是频率
  3. 对于难点2,就维护k个高频元素的一个有序的集合,就用到了大根堆或者小根堆,这个数据结构很适合求很大数据集里的前k个高频或者低频的结果
  4. 如何用堆求前k个高频元素呢?只需要用堆来遍历map里边的所有元素,然后堆里维持k个元素,然后遍历完后堆里的k个元素就题目所求。问题来了用大根堆还是小根堆呢?其实应该用小根堆的,因为用大根堆的话,因为堆pop元素时只能从堆顶弹出,用大根堆的话就把最大的弹出了,因此不行。那么用小根堆把小的都弹出,最后剩下k个元素就是要求的了

2.2 代码

//解法2:基于小顶堆实现
    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;
    }
相关文章
|
26天前
|
算法
【算法】滑动窗口——最大连续1的个数
【算法】滑动窗口——最大连续1的个数
|
26天前
|
算法
【算法】滑动窗口——将x减到0的最小操作数
【算法】滑动窗口——将x减到0的最小操作数
|
26天前
|
算法 容器
【算法】滑动窗口——串联所有单词的子串
【算法】滑动窗口——串联所有单词的子串
|
27天前
|
存储 算法
【C算法】编程初学者入门训练140道(1~20)
【C算法】编程初学者入门训练140道(1~20)
|
26天前
|
算法
【算法】滑动窗口——最小覆盖子串
【算法】滑动窗口——最小覆盖子串
|
26天前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
26天前
|
算法
【算法】滑动窗口——无重复字符的最长子串
【算法】滑动窗口——无重复字符的最长子串
|
26天前
|
算法
【算法】滑动窗口——长度最小的子数组
【算法】滑动窗口——长度最小的子数组
|
1月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
34 6
|
1月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
35 1
下一篇
DDNS