前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;

    }
};

原文地址:https://www.cnblogs.com/gzyc/p/10724310.html

时间: 2024-08-11 09:56:21

前K个高频元素的相关文章

[LeetCode] Top K Frequent Elements 前K个高频元素

Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2,2,3] and k = 2, return [1,2]. Note: You may assume k is always valid, 1 ≤ k ≤ number of unique elements.    Your algorithm's time complexity must be

347 Top K Frequent Elements 前K个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素.例如,给定数组 [1,1,1,2,2,3] , 和 k = 2,返回 [1,2].注意:    你可以假设给定的 k 总是合理的,1 ≤ k ≤ 数组中不相同的元素的个数.    你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小.详见:https://leetcode.com/problems/top-k-frequent-elements/description/C++: class Solution { pub

[LeetCode]347. 前 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?是数组的大小. 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problem

LeetCode347:返回频率前K高的元素,基于优先队列实现

package com.lt.datastructure.MaxHeap; import java.util.LinkedList; import java.util.List; import java.util.TreeMap; import com.lt.datastructure.Queue.PriorityQueue; /** LeetCode347 给定一个非空的整数数组,返回其中出现频率前 k 高的元素. 示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输

从一个序列中获取前K大的数的一种方法

这个方法是利用快速排序的.在快速排序中,得到中间元素(pivot)之后,比较中间元素之前的元素个数和K的大小关系,从而确定后面该往哪个方向继续递归.如果中间元素前面的元素个数等于K,那就停止递归过程:如果中间元素前面元素个数小于K,那就再中间元素后面进行递归:否则就往中间元素前面进行递归.这样最终得到的是没有排序的前K大的元素,这样再对前K个元素进行一次真正的快速排序.这样就能得到排好序的前K大元素.我随机生成了一个100000个整型数据的文件进行测试,求前10000个元素.这样做用了0.984

关于leetcode第K个最大元素的几种解法

对于这一题我使用了最大堆,快速排序,归并排序几种解法来做这一题,速度最快的是归并排序 使用定值的最小堆每次更新数组最后剩下前k个最大元素,而且堆顶就是我们要的第K个元素. 堆排序: import heapq class Solution(object): def findKthLargest(self, nums, k): """ :type nums: List[int] :type k: int :rtype: int """ self.mi

堆的应用(1000个数据中找最大的前K个元素,堆排序)

(1)从1000个数据中找到k个最大数据 首先看到这个题时,可能会想到先将这1000个数据进行降序排序,即取出的前k个元素最大.时间复杂度为O(N^2),使得程序效率低. 如何解决这个问题呢?我们的堆就派上用场喽! 解题思路: 可先创建一个数组topK[k],将100w中的前k个数据放入数组topK中,将topK中的数据建小堆,则可保证堆的第一个元素是最小的,将第k个元素与堆中第一个元素比较,若大于,则交换.对堆进行重新建小堆,取第k+1个元素与堆中第一个元素比较,以此类推,直至100w-k个元

算法导论学习之线性时间求第k小元素+堆思想求前k大元素

对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思路例如以下: 1.分解:将A[p,r]分解成A[p,q-1]和A[q+1,r]两部分.使得A[p,q-1]都小于A[q],A[q+1,r]都不小于A[q]; 2.求解:假设A[q]恰好是第k小元素直接返回,假设第k小元素落在前半区间就到A[p,q-1]递归查找.否则到A[q+1,r]中递归查找. 3

若干个(大量)数字中找前K大/小的元素--数值型

方法一:根据快速排序划分的思想 : (1) 递归对所有数据分成[a,b)b(b,d]两个区间,(b,d]区间内的数都是大于[a,b)区间内的数 : (2) 对(b,d]重复(1)操作,直到最右边的区间个数小于100个. 注意[a,b)区间不用划分 :因为[a,b)区间一定小于(b,d]区间: (3) 返回上一个区间,并返回此区间的数字数目. 如果个数大于100,对(b,d]重复(1)操作,直到最右边的区间个数小于100个: 如果个数小于100,对上一区间的左边进行划分,分为[a2,b2)b2(b