Leetcode刷题-347:前 K 个高频元素

1.题目描述

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例1:

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

示例2:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/top-k-frequent-elements

2.题目分析

2.1 使用优先队列

前面的文章已经介绍过优先队列解题的思路,这篇文章对优先队列的介绍很详细。这道题依然可以使用一个存储pair数据的优先队列priority_queue来解题。此时pair中的k-v关系应当是:频率-元素值;因为默认的优先队列是一个大顶堆,所以我们直接使用它的话就选择将数组内所有的频率-元素值对存储到优先队列中,此时会根据频率进行自动的排序,到所有的pair元素插入队列之后,我们输出k次堆顶元素(也就是队首元素),就完成了最高频的前k个元素。

对于优先队列所需要存储的频率-元素值对的求法,可以通过对数组进行排序,然后在再次遍历数组的时候累计求得。具体代码如3.1所示。

2.2 使用小顶堆

前面直接使用大顶堆的话,虽然时间复杂度上较为可以,但是我们发现,需要存储所有元素的频率-元素值对,这就造成很大的空间浪费。既然题目是要求我们求解前k个高频元素,那么其实我们每次只维护k个元素的队列就可以了。我们可以设想出这样的流程

在一个空间维护k个元素,每当有一个新的元素P需要加入的时候,我们就看这个空间的最小的元素min是否大于这个待加入元素。如果min>P,则说明P不是前k个最大的元素;否则的话,p>min,min就应该被淘汰。

但这样的话是无法靠大顶堆实现的。因为大顶堆的堆顶是最大元素,而且我们无法简单的查找出当前堆哪个元素最小。与大顶堆对应的一个数据结构——小顶堆,则可以实现这样的操作。于是我们试图用小顶堆来进行优先队列的初始化。

2.3 基于快排的partition算法划分数组

既然是求前k个值,那么我们可以想到快排中的partition算法就是根据基准元素将数组划分为两个部分,基准元素前面和后面的分别可以是大于基准元素和小于基准元素的值。这就很契合我们这道题了。快排的具体实现可以看这篇文章

在这道题运用快排基准划分的方法的话,我们需要将map保存的键值对存储到vector进行处理,因为vector可以进行高效的基于下标的交换元素。但是由于各个数据结构的特性,在元素值-频率键值对存储的时候还是要用到map结构。

所以我们的实现代码就如3.3所示,代码注释解释了解题思路。

3.题目解答

3.1 直接使用优先队列——大顶堆

class Solution {
   
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
   
        int len = nums.size();
        sort(nums.begin(),nums.end());
        priority_queue<pair<int,int>> que;
        for(int i=0;i<len;i++){
   
            int p=1;
            while(i+
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值