347. Top K Frequent Elements
Total Accepted: 12022 Total Submissions: 28556 Difficulty: Medium
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 better than O(n log n), where n is the array's size.
【题意】
输入一个存储整型数据的非空数组,返回出现频次最多的前k个元素。
【分析】
step1.显然,为了找出数组中出现频次最多的前k个元素,首先,我们需要分别统计出数组中各个元素出现的频次,很容易想到哈希表,Java中提供了HashMap类,它实现了Map接口,HashMap是一个泛型类(HashMap<key,value>),可以用来存储键/值对,为了统计数组个元素的频次,我们可以把元素数值作为“键”,对应元素出现的次数作为“值”,如此,我们只需要对数组进行一次遍历就可以得到一张包含不同数组元素和对应出现频次的“映射表”。
step2.由于我们关心的是出现频次最多的前k个元素,因此,得到频次统计“映射表”之后,我们需要根据频次对映射表中的键/值对进行排序。
step3. 映射表中键(数据元素)和值(该数据元素出现的频次)是一一对应的,我们在按值进行排序的同时需要记录其对应的元素,鉴于此,我们可以采用“桶排序”的思想。由于我们是按数据元素出现的频次进行排序的,那么“桶”的数量范围是可以确定的——桶的数量小于等于给定数组元素的个数。编号为i的桶用于存放数组中出现频次为i的元素——即编号为i的桶存放“映射表”中“值”等于i的“键”。
step4. 排序完成后,编号大的桶中元素出现的频次高,因此,我们“逆序”(先取桶编号大的桶的元素)获取桶中数据,直到获取数据的个数等于k,我们将当前桶的元素取尽(同一个桶中元素出现的频次相等),然后停止取数据,完成!
【程序】
基于Java的程序如下:
public class Solution {
public List<Integer> topKFrequent(int[] nums, int k)
{
//step1—用哈希表统计数组中各元素出现的频次,表中“键”为元素数值,“值”为对应元素出现的频次
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int num:nums)//遍历数组
{
if(map.get(num)==null)//如果“键”为num的数据首次出现,则“值”设为1
map.put(num, 1);
else
map.put(num, map.get(num)+1);//重复出现,则累计频次
}
//step2—桶排序
List<Integer>[] bucket=new List[nums.length+1];//定义足够数量的桶
for(int key:map.keySet())//按“键”遍历
{
int count=map.get(key);//获取数值为key的元素出现的频次
//把出现频次相同的元素“扔”到序号等于频次的桶中
if(bucket[count]==null)
bucket[count]=new ArrayList<Integer>();
bucket[count].add(key);
}
//step3—“逆序”取数据
List<Integer> result=new ArrayList<Integer>();
for(int i=nums.length;i>0;i--)//注意i的起始值,当数组只有一个数据时
{
if(bucket[i]!=null&&result.size()<k)
result.addAll(bucket[i]);
}
return result;
}
}
【运行结果】
You are here!
Your runtime beats 76.92% of javasubmissions.