• 前K个高频元素


    数据结构--堆

    • Heap是一种数据结构具有以下的特点:

      1)完全二叉树;

      2)heap中存储的值是偏序;

    • Min-heap: 父节点的值小于或等于子节点的值;

    • Max-heap: 父节点的值大于或等于子节点的值;

    1.堆的存储:

    一般都用数组来表示堆,i结点的父结点下标就为(i–1)/2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2

    2.堆的操作:insert

    插入一个元素:新元素被加入到heap的末尾,然后更新树以恢复堆的次序。
    每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于直接插入排序中将一个数据并入到有序区间中。

    3.堆的操作:Removemax

    按定义,堆中每次都删除第0个数据。为了便于重建堆,实际的操作是将最后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最大的,如果父结点比这个最小的子结点还大说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一个数据的“下沉”过程。

    4.堆的操作:buildHeap 堆化数组

    对于叶子节点,不用调整次序,根据满二叉树的性质,叶子节点比内部节点的个数多1.所以i=n/2 -1 ,不用从n开始

    5.堆排序

    堆建好之后堆中第0个数据是堆中最大的数据。取出这个数据再执行下堆的删除操作。这样堆中第0个数据又是堆中最大的数据,重复上述步骤直至堆中只有一个数据时就直接取出这个数据。

    priority_queue

    1. priority_queue允许用户为队列中元素设置优先级,放置元素的时候不是直接放到队尾,而是放置到比它优先级低的元素前面,标准库默认使用<操作符来确定优先级关系。

    2. priority_queue模板类有三个模板参数:元素类型,容器类型,比较算子。其中后两个可以省略,默认容器为vector,默认算子为less,即如果x<y判断为真,则y排到x前面,y先出队。

    3. priority_queue<int,vector,greater> q3;//定义优先级小的先出队

    4. priority_queue与queue的基本操作均相同,在使用q.top()时返回最高优先级的元素,该操作只适用于优先级队列。

    pair

    1. pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。

    2. make_pair函数:

       template pair make_pair(T1 a, T2 b) { return pair(a, b); }
      

    很明显,我们可以使用pair的构造函数也可以使用make_pair来生成我们需要的pair。 一般make_pair都使用在需要pair做参数的位置,可以直接调用make_pair生成pair对象很方便,代码也很清晰。 另一个使用的方面就是pair可以接受隐式的类型转换,这样可以获得更高的灵活度。

    类模板:template <class T1, class T2> struct pair
    参数:T1是第一个值的数据类型,T2是第二个值的数据类型。
    功能:pair将一对值组合成一个值,这一对值可以具有不同的数据类型(T1和T2),两个值可以分别用pair的两个公有函数first和second访问。

    1. 生成新的pair对象

    可以使用make_pair对已存在的两个数据构造一个新的pair类型:

    int a = 8; 
    string m = "James"; 
    pair<int, string> newone; 
    newone = make_pair(a, m);
    

    using 别名指定

    在C++11中提出了通过using指定别名

    using value_type = _Ty
    

    以后使用value_type value; 就代表_Ty value;

    #include <bits/stdc++.h>
    

    开始今天的题目

    给定一个非空的整数数组,返回其中出现频率前 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 是数组的大小。

    解析:

    topk (前k大)用小根堆,维护堆大小不超过 k 可。每次压入堆前和堆顶元素比较,如果比堆顶元素还小,直接扔掉,否则压入堆。检查堆大小是否超过 k,如果超过,弹出堆顶。复杂度是 nlogk

    避免使用大根堆,因为你得把所有元素压入堆,复杂度是 nlogn,而且还浪费内存。如果是海量元素,那就挂了。

    [注意]
    求前 k 大,用小根堆,求前 k 小,用大根堆。面试的时候如果说反了会挂!

    代码

    class Solution {
    public:
        vector<int> topKFrequent(vector<int>& nums, int k) {
    
          using  E =  pair<int,int>;
           priority_queue<E,vector<E>,greater<E>> minHeap;//优先级小的在栈顶,即值小的先出栈
            map<int,int> counter;
            for(auto e :nums){
                ++counter[e];//记录出现的频率
            }
            for(auto & x:counter){//加个引用如果需要改变X的值就必须得有
                auto pair  = make_pair(x.second,x.first);
                if(minHeap.size() == k){//保证前K
                    if(pair < minHeap.top()) continue;
                    minHeap.pop();
                }
                minHeap.push(pair);
                
            }
            vector<int> res (minHeap.size());
            k = res.size();
            while(!minHeap.empty()){
                res[--k] = minHeap.top().second;
                minHeap.pop();
            }
            return res;
            
        }
    };
  • 相关阅读:
    TestMap HashMap的常见操作
    三种方式遍历一颗二叉树
    jmeter 5.1.1版本 进行抓包的时候弹出输入密码
    浅谈Java中的AOP面向切面的变成和控制反转IOC
    rpc测试框架
    SpringBoot下,@WebFilter配置获取日志
    某些测试工具
    Google的三大马车
    关于Mock的一些网站
    用Jmeter做性能测试,之后报表展示
  • 原文地址:https://www.cnblogs.com/gzyc/p/10724310.html
Copyright © 2020-2023  润新知