一招打通优先队列解决前K大/小 XXXX 的问题

前 K 个高频元素

问题描述 :

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

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

输出: [1,2]

示例 2:

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

输出: [1]

说明:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。

你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。

输出时,首先输出频率最高的元素,如果频率相同,则先输出元素值较大的元素。

输入说明 :

首先输入nums数组的长度n,

然后输入n个整数,以空格分隔。

最后输入k。

输出说明 :

首先输出频率最高的元素,如果频率相同,则先输出元素值较大的元素。

元素之间以空格分隔。

输入范例 :
在这里插入图片描述

分析:典型的优先队列问题,关键在于是建立最大堆还是最小堆,判断的标准就是“反着来”。如果求前K大XXX,就构建最小堆;反之亦然。
代码有很多相似之处,模板式往上套,在下面代码中标注。
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
vector<int> topKFrequent( vector<int> &nums,int k){
   map<int,int> m;
    priority_queue< pair<int,int>, vector< pair<int,int> >, greater< pair<int,int> > > pq;
    int i;
    //用map统计各个数字出现的频度
    for(i=0;i<nums.size();i++){
       m[nums[i]]++;
    }
   //维护k大小的最小堆
   map<int,int>::iterator it;
   //将map内容按照元素数值从大到小先进行排序
   
  //解释:为什么在加入队列中时,将频度放在pair第一个位置,元素放在pair的second位置,是因为最小堆默认,如果第一个元素值相等,则second位置元素大的在前面。这样就保证了题目中要求的如果频度相等,元素值大的排在前面的要求。
   for(it=m.begin();it!=m.end();it++){
   //模板开始
        if(pq.size()==k){//如果优先队列中的二元素个数为k
            if(it->second > pq.top().second){//最小堆比较:此时元素>对头元素
                pq.pop();//弹出队头
                pq.push(make_pair(it->second,it->first));//将此时元素键入队列中
            }
        }
        else{		//如果队列中元素的个数小于K,直接进入队列
            pq.push(make_pair(it->second,it->first));
        }

    }
   //模板结束
   //处理结果
    vector<int> res;
    while(!pq.empty()){
        res.push_back(pq.top().second);
        pq.pop();
    }
    reverse(res.begin(),res.end());//最小堆是按照升序排列的,所以要来个反转。
    return res;
}

int main()

{

    int n,data,k;

    vector<int> nums;

    cin>>n;

    for(int i=0; i<n; i++)

    {

        cin>>data;

        nums.push_back(data);

    }

    cin>>k;

    vector<int> res=topKFrequent(nums,k);

    for(int i=0; i<res.size(); i++)

    {

        if (i>0)

            cout<<" ";

        cout<<res[i];

    }

    return 0;

}


查找和最小的K对数字

问题描述 :

给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k。

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。

找到和最小的 k 对数字 (u1,v1), (u2,v2) … (uk,vk),按从小到大的顺序输出它们的和。

示例 1:

输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3

输出: 因为前三对是:[1,2],[1,4],[1,6],所以输出3,5,7

解释: 返回序列中的前 3 对数:

[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

示例 2:

输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2

输出: 2, 2

解释: 返回序列中的前 2 对数:

[1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

示例 3:

输入: nums1 = [1,2], nums2 = [3], k = 3

输出: 总共只有两对:[1,3],[2,3],所以输出4, 5

解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]

输入说明 :

首先输入nums1的长度n,然后输入n个整数

再输入nums2的长度m,然后输入m个整数

最后输入k

输出说明 :

按从小到大的顺序输出k对数字的和(注意:可能不足k对)

输入范例 :

有了上面一道题的分析,这道题就easy了,直接往上套,这道是构建最大堆。
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
//构建最大堆
struct cmp{
    bool operator()(pair<int,int> &a,pair<int,int> &b){
        return a.first+a.second<b.first +b.second;
    }
};

 vector<vector<int> > kSmallestPairs(vector<int>&nums1,vector<int>&nums2,int k){
//按照常理来说,默认构造的是最大堆,或者用lesser。可是不加cmp,就是不出来结果,也不知道为啥,记住就行了,构建最小堆时直接用greater,最大堆时来个cmp
    priority_queue<pair<int, int>, vector<pair<int, int> >, cmp> pq;   //最大堆

    int i;
    //下面是模板
    for(i=0;i<nums1.size();i++){
        for(int j=0;j<nums2.size();j++){
            if(pq.size()==k){
                if(pq.top().first+pq.top().second>nums1[i]+nums2[j]){
                    pq.pop();
                    pq.push(make_pair(nums1[i],nums2[j]));
                }
            }
                else
                    pq.push(make_pair(nums1[i],nums2[j])}
    }
    vector<vector<int> > res;

		while (!pq.empty()) {

			vector<int> temp;
			temp.push_back(pq.top().first);
			temp.push_back(pq.top().second);
			pq.pop();
			res.push_back(temp);

		}
    return res;
 }
int main()

{

    int n,m,data,k;

    vector<int> nums1,nums2;

    cin>>n;

    for(int i=0; i<n; i++)

    {

        cin>>data;

        nums1.push_back(data);

    }

    cin>>m;

    for(int i=0; i<m; i++)

    {

        cin>>data;

        nums2.push_back(data);

    }

    cin>>k;

    vector<vector<int> > res=kSmallestPairs(nums1,nums2,k);

    for(int i=0; i<res.size(); i++)

    {

        if (i>0)

            cout<<" ";

        cout<<res[i][0]+res[i][1];

    }

    return 0;

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值