求前K个最大数,或第K个最大数或第K大频率的单词类似问题小结

求前K个最大数,最小数,第K个最大数,或者 出现频率为第K大的单词是哪个 此类问题,首先想到的就是排序,但是求第K最大而已,并不要求完全有序,所以 想到了 大顶堆 和小顶堆

我们可以用到 优先级队列 priority_queue,它实际上是一个队列,但是它的功能是始终保持队首元素是当前元素的最大值

定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 是仿函数,决定了优先队列的 比较方式

默认为大顶堆:priority_queue<int,vector<int>,less<int>>

当然也可以自定义类型然后自定义相匹配的仿函数

 

1.首选由简单的例题着手:

本题要求数组中第K大的数是多少?

第一想法是进行排序,然后选择合适位置处的元素即可

但是要求是求第K大元素,并不要求对数组进行排序

所以我们只要知道前K个最大元素即可,而对于他们的顺序无关紧要,所以就可以用到优先级队列priority_queue

将数组元素逐渐压入priority_queue,当优先级队列内的元素 大于 (所有元素个数 - k)时,即优先级队列顶端中一定是前K个元素中的某一个了

取出顶端元素压入 数组中,然后找到数组中的最小元素,即为全部元素中的第K大元素

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
        vector<int> restmp;
        priority_queue<int> pq;//优先级队列
        for(auto i : nums)
        {
            pq.push(i);
            if(pq.size() > nums.size()-k)
            {
                restmp.push_back(pq.top());
                pq.pop();
            }
        }
        int kmin  =INT_MAX;
        for(int i : restmp)
        {
            if(i <= kmin)
            {
                kmin = i;
            }
        }
        return kmin;
    }
};

2.求数组中,出现频率位于前K次的元素

这题目也不难,容易想到的就是用 哈希map来统计每一个元素出现的次数

然后用优先级队列,但由于 比第一题多了 要考虑的频率,所以我们采用 对组 pair<int,int>容器

来记录各个元素出现的频率以及对应的元素。

然后求前K个,用默认的大顶堆即可

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) 
    {
        unordered_map<int,int> map;
        vector<int> res;
        for(int i = 0; i < nums.size(); i++)//统计每个元素的出现的频率
        {
            map[nums[i]]++;
        }
        priority_queue<pair<int,int>> pq; //用大顶堆来记录 频率和对应元素,
        //用pair的第一个元素代表频率,第二个元素代表对应该频率对应的元素
        
        for(auto it = map.begin(); it != map.end(); it++)
        {
            pq.push(make_pair(it->second,it->first));
            if(pq.size() > map.size()-k)
            {
                res.push_back(pq.top().second);
                pq.pop();
            }
        }
        return res;
    }
};

3.求数组中出现频率为与前K的单词

本来,这道题目和第二题是一样的,只不过把 数据元素 换位 单词元素即可

虽然要求 单词的频率求出现最多的前K个,但是当两个单词出现频率相同时,并不是要求随意摆放,结果中要求

频率相等时,单词按字典顺序摆放,即升序摆放

所以,问题出现了,频率按降序,频率相同时,单词按升序

显然,要定义自己的仿函数

 由于也是用对组 pair<int,string>来记录频率和对应的单词;对组中第一个元素代表频率

所以,仿函数

    struct fun
    {
        bool operator()(pair<int,string>& p1, pair<int,string>& p2)
        {
            if(p1.first < p2.first)//这样记忆吧,小于号代表降序,大于到代表升序
            {
                return true;
            }
            else if(p1.first > p2.first)
            {
                return false;
            }
            else
            {
                if(p1.second > p2.second)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    };

所以完整程序如下:

class Solution {
public:
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        vector<string> res;
        unordered_map<string,int> map;
        for(auto word : words)
        {
            map[word]++;
        }
        priority_queue<pair<int,string>,vector<pair<int,string>>,fun> pq;
        
        for(auto it = map.begin(); it != map.end(); it++)
        {
            pq.push(make_pair(it->second,it->first));

        }
        while(pq.size() > map.size()-k)
        {
            res.push_back(pq.top().second);
            pq.pop();
        }
        return res;
    }
    
private:
    struct fun
    {
        bool operator()(pair<int,string>& p1, pair<int,string>& p2)
        {
            if(p1.first < p2.first)//这样记忆吧,小于号代表降序,大于到代表升序
            {
                return true;
            }
            else if(p1.first > p2.first)
            {
                return false;
            }
            else
            {
                if(p1.second > p2.second)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    };
    
};


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值