• 前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;
            
        }
    };
  • 相关阅读:
    _bzoj1061 [Noi2008]志愿者招募【最小费用最大流】
    _bzoj2243 [SDOI2011]染色【树链剖分】
    _bzoj1013 [JSOI2008]球形空间产生器sphere【高斯消元】
    _bzoj1002 [FJOI2007]轮状病毒【瞎搞】
    leetcode 273 Integer to English Words
    leetcode 12 Integer to Roman
    leetcode 1071 Greatest Common Divisor of Strings
    lc6 ZigZag Conversion
    lc13 Roman to Integer
    leetcode 171 Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/gzyc/p/10724310.html
Copyright © 2020-2023  润新知