面试题 17.14. 最小K个数 347. 前 K 个高频元素

面试题 17.14. 最小K个数

题目

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例:

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]
提示:

0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))

class Solution {
public:
    vector<int> smallestK(vector<int>& arr, int k) {
        int len = arr.size();
        if (len <= k)
            return arr;
        
        vector<int> res;
        priority_queue<int> maxHeap;
        for (int i = 0; i < len; ++i) {
            maxHeap.push(arr[i]);
            if (maxHeap.size() > k)
                maxHeap.pop();
        }
        while (!maxHeap.empty()) {
            res.push_back(maxHeap.top());
            maxHeap.pop();
        }

        return res;
    }
};

347. 前 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 个高频元素的集合是唯一的。
你可以按任意顺序返回答案。

 解法:

class Solution {
public:
#define PAIR pair<int, int>                                   //简写类型
class cmp {                                                   //重写比较函数,小堆顶
public:                                                       //不可省略
    bool operator()(const PAIR& left, const PAIR& right) {
        return left.second > right.second;
    }
};                                                            //标点符号

    vector<int> topKFrequent(vector<int>& nums, int k) {
        int len = nums.size();
        if (k == 0)
            return vector<int>();
        if (k == len)
            return nums;

        unordered_map<int, int> map;                          //用hash计数
        for (int i = 0; i < len; ++i)
            ++map[nums[i]];

        
        priority_queue<PAIR, vector<PAIR>, cmp> heap;        //用堆对计数的结果进行排序,三个参数
        for (auto it = map.begin(); it != map.end(); ++it) {
            heap.push(*it);
            if (heap.size() > k)
                heap.pop();
        }

        vector<int> res(k);                                  //存入结果
        for (int i = 0; i < k; ++i) {
            res[i] = heap.top().first;
            heap.pop();
        }

        return res;
    }
};

 注意cmp的写法,是>,即小堆,先把小数pop掉。

扫描二维码关注公众号,回复: 13104521 查看本文章

priority_queue

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

  • 插入:先添加到尾部,然后不断与父节点比较,不断上升。
  • 删除:先将根节点与最后一个节点交换位置,然后将最后一个节点(即原来的根节点)弹出

       当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。没有迭代器,不允许遍历。

       在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。

和队列基本操作相同:

  • top 访问队头元素
  • empty 队列是否为空
  • size 返回队列内元素个数
  • push 插入元素到队尾 (并排序)
  • emplace 原地构造一个元素并插入队列
  • pop 弹出队头元素
  • swap 交换内容
//升序队列,小顶堆
priority_queue <int,vector<int>,greater<int> > q;
//降序队列,大顶堆,默认
priority_queue <int,vector<int>,less<int> >q;

/// heap默认为大堆,以下设置为建立小堆
template <typename T>
struct greator
{
    bool operator()(const T &x, const T &y)
    {
        return x > y;
    }
};

   //greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

1:用pair做优先队列元素的例子:

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
    priority_queue<pair<int, int> > a;
    pair<int, int> b(1, 2);
    pair<int, int> c(1, 3);
    pair<int, int> d(2, 5);
    a.push(d);
    a.push(c);
    a.push(b);
    while (!a.empty())
    {
        cout << a.top().first << ' ' << a.top().second << '\n';
        a.pop();
    }
}

:2:用自定义类型做优先队列元素的例子

#include <iostream>
#include <queue>
using namespace std;

//方法1
struct tmp1 //运算符重载<
{
    int x;
    tmp1(int a) {x = a;}
    bool operator<(const tmp1& a) const
    {
        return x < a.x; //大顶堆
    }
};

//方法2
struct tmp2 //重写仿函数
{
    bool operator() (tmp1 a, tmp1 b)
    {
        return a.x < b.x; //大顶堆
    }
};

int main()
{
    tmp1 a(1);
    tmp1 b(2);
    tmp1 c(3);
    priority_queue<tmp1> d;
    d.push(b);
    d.push(c);
    d.push(a);
    while (!d.empty())
    {
        cout << d.top().x << '\n';
        d.pop();
    }
    cout << endl;

    priority_queue<tmp1, vector<tmp1>, tmp2> f;
    f.push(b);
    f.push(c);
    f.push(a);
    while (!f.empty())
    {
        cout << f.top().x << '\n';
        f.pop();
    }
}

c++优先队列(priority_queue)用法详解

猜你喜欢

转载自blog.csdn.net/sy_123a/article/details/108530851