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

239.滑动窗口最大值

链接:LeetCode239.滑动窗口最大值
思路:
刚开始假设使用的是栈,当栈空时元素入栈。当栈不为空且当前元素小于栈顶元素,元素入栈。当栈不为空,当前元素大于栈顶元素,栈顶出栈直到当前元素小于栈顶元素。当当前的元素下标i+1>=k时,可以寻找窗口内的最大元素,此时栈底元素为当前窗口最大值。此时栈结构已经不满足当前的操作,既可以从顶部删除插入元素又可以从底部取出元素,可以选取deque作为该题的数据结构。为了满足当前的最大元素在当前的窗口内,需要将元素和对应的下标位置做一个映射。将其存储到pair<int,int>中。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        //用队列
        deque<pair<int,int>> qu;vector<int> ans;
        for(int i=0;i<nums.size();++i){
            while(!qu.empty() && qu.back().first<=nums[i]) qu.pop_back();
            qu.push_back(pair<int,int>{nums[i],i});
            //保证在同一个窗口
            if(i+1 >= k) {
                while(!qu.empty() && qu.front().second<i+1-k) qu.pop_front();
                ans.push_back(qu.front().first);
            }
        }
        if(nums.size()<k) ans.push_back(qu.front().first);
        return ans;
    }
};

347.前K个高频元素

链接:LeetCode347.前K个高频元素
思路:

  1. 将元素和其出现的次数做一个映射。按照元素出现的次数从大到小进行排序。输出前K个元素。
  2. 借用堆排序的思想,选取优先级队列作为作为本题的数据结构。并且排序方法为:以key:value;中的value值为依据的小根堆。(为什么选用小根堆呢?因为大根堆只能满足第一个元素是所有元素中最大的,而不能保证其余k-1个元素是次大的)。

错误代码

class Solution {
public:
    typedef pair<int,int> pa;
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //映射元素和其出现的次数
        unordered_map<int,int> ma;
        for(const int&num:nums) ++ma[num];

        if(nums.size()<=k) return nums;

        //开始寻找出现频率前k高的元素
        priority_queue<pa,vector<pa>,less<pa>> qu;//小根堆
        for(auto it = ma.begin();it!=ma.end();++it) {
            if(qu.size()<k) qu.push(pa{it->second,it->first});
            else if(it->second>qu.top().first) 
            {qu.pop();qu.push(pa{it->second,it->first});}
        }
        vector<int> ans;
        while(k--) {ans.push_back(qu.top().second);qu.pop();}
        return ans;
    }
};
代码分析
  1. 写的第一版代码中,是将元素出现的次数作为key值,元素的数值作为value值存储在pair中再将其加入到优先级队列中(因为优先级队列是按照key值进行排序的)。但是却忽略了一种很关键的情况:不同的数值出现的次数一致,这种情况下只能保存一个键值对,会自动舍弃掉其它元素。改正方法就是:元素的数值作为key值,出现的次数作为value值。写一个按照value值排序的小根堆。

正确代码

class Solution {
public:
    typedef pair<int,int> pa;
    class myfun{
    public:
        //必须将函数设置成public不然外部无法访问
        bool operator ()(const pa&p1,const pa&p2){
            return p1.second>p2.second;//小根堆
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //映射元素和其出现的次数
        unordered_map<int,int> ma;
        for(const int&num:nums) ++ma[num];

        if(nums.size()<=k) return nums;

        //开始寻找出现频率前k高的元素
        priority_queue<pa,vector<pa>,myfun> qu;//小根堆
        for(auto it = ma.begin();it!=ma.end();++it) {
            //cout << it->first<<"  "<<it->second;
            if(qu.size()<k) qu.push(*it);
            else if(it->second > qu.top().second) {qu.pop();qu.push(*it);}
        }
        vector<int> ans(k,0);int in=0;
        while(k--) {ans[in++] = qu.top().first;qu.pop();}
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值