【代码随想录算法训练营14期】Day13- 第五章 栈与队列part03

Day11- 第五章 栈与队列part03


今日内容:

● 239. 滑动窗口最大值
● 347.前 K 个高频元素

今日知识点:

● 优先队列

文章目录

  • Day11- 第五章 栈与队列part03
  • 239. 滑动窗口最大值
    • 1、解题思路
    • 2.代码
  • 347. 前 K 个高频元素
    • 1.解题思路
    • 2.代码
  • 总结


239. 滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

示例 1:

输入: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


1、解题思路

滑动窗口最大值,滑动窗口类似单向队列,构建一个单向递减的队列,这样就能保证每次取队列的队头即为窗口最大值;每遍历一个数字a,就要在队列不空的情况下,循环与队尾的数比较,(这里解释一下因为队列是严格递减的,所以只用和队尾元素比较,队尾之前的队列已经严格递减了,相当于把队列元素中比a小的所有数出队)如果a大于队尾元素,那么队尾元素就要出队,直到队列为空或者a小于某一个队尾元素,那么a入队;当新的数入队的时候还需要判断队内元素个数是否小于等于k,这里不能使用size()函数,可以使用数组下标记录其位置队列中下标应该从[i-k+1,i], while(res.front() <= i - k) res.pop_front();这里bug一直没通过。

2.代码

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;
        deque<int> res;
        for(int i = 0; i < k ; i++){
            while(!res.empty() && nums[i] >= nums[res.back()]){
                res.pop_back();
            }
            res.push_back(i);
        }
        ans.push_back(nums[res.front()]);
        for(int i = k; i < nums.size(); i++){
            while(!res.empty() && nums[i] >= nums[res.back()]){
                res.pop_back();
            }         
            res.push_back(i);
            while(res.front() <= i - k)
                res.pop_front();
            ans.push_back(nums[res.front()]);
        }
        return ans;
    }
};

347. 前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]


1.解题思路

解题思路很简单,使用map记录下每个数出现的次数,然后对value进行排序,这里使用小顶堆,设置堆的元素k个,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素,这里对堆不太熟悉,代码陌生。

2.代码

class Solution {
public:
    static bool cmp(pair<int, int>& m, pair<int, int>& n) {
        return m.second > n.second;
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int,int> res;
        for(int i = 0; i < nums.size(); i++)
            res[nums[i]]++;
        //建立一个小顶堆
        priority_queue<pair<int,int>, vector<pair<int,int>>,decltype(&cmp)> prique(cmp);
        //
        for(auto& [num,count] : res){
            if(prique.size() == k){
                if(prique.top().second < count){
                    prique.pop();
                    prique.emplace(num,count);
                }
             }
            else
                prique.emplace(num,count);    
        }
        vector<int> ans;
        while(!prique.empty()){
            ans.emplace_back(prique.top().first);
            prique.pop();
        }
        return ans;
    }
};

总结

  1. 优先队列

priority_queue:优先队列,本质是堆实现。与队列不同的是,priority_queue只能访问队列头部的信息(使用top),且插入元素后,会自动排序。

  1. 基本操作

top(): 访问队头元素
empty(): 队列是否为空
size():返回队列内元素个数
push():插入元素到队尾 (并排序)
emplace():原地构造一个元素并插入队列
pop():弹出队头元素
swap():交换内容

  1. 定义

priority_queue

Type :优先队列中元素的数据类型

Container :容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector)【简单理解就是用什么容器实现这个优先级队列】

Functional :比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆【有greater、less和自定义函数,其中greater使得优先队列中的元素升序排列,所以第一个元素(头部)就是最小的元素,也就是小顶堆;less使得元素降序排列,那么第一个元素就是最大的,也就是大顶堆。】

你可能感兴趣的:(代码随想录算法训练营,算法,数据结构,leetcode)