给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
题解(一):哈希表+数组迭代,利用哈希表存储每一个数字出现的次数,再遍历哈希表,利用数组存储频率前k高的元素(我们需要用到迭代的方法,实时更新数组中的元素)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer>map=new HashMap<>();
for(int x:nums){
int temp=map.getOrDefault(x,0);
map.put(x,temp+1);
}
int[]res=new int[k];
Set<Integer>key=map.keySet();
for(int x:key){
int value=map.get(x);
for(int i=0;i<res.length;i++){
if(!map.containsKey(res[i])){
res[i]=x;
break;
}
else if(value>=map.get(res[i])) {
move(i, res, x);
break;
}
}
}
return res;
}
private void move(int i,int[]res,int x){
for(int k=res.length-1;k>i;k--){
res[k]=res[k-1];
}
res[i]=x;
}
}
题解(二):哈希表+堆,我们可以在题解(一)的基础上进行优化,将数组换成最大堆,堆中前k个元素就是频率前k高的元素
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer>map=new HashMap<>();
for(int x:nums){
map.put(x,map.getOrDefault(x,0)+1);
}
Queue<int[]>order=new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o2[1]-o1[1];
}
});
Set<Integer>key=map.keySet();
for(int x:key){
order.offer(new int[]{
x,map.get(x)});
}
int[]res=new int[k];
for(int i=0;i<k;i++){
res[i]= Objects.requireNonNull(order.poll())[0];
}
return res;
}
}
题解(三):快排+堆,将给定数组进行升序排列之后,就不再需要用到哈希表,直接遍历数组就可以得到每个数字的频率,再将其添加到堆中,就可以得到前k个高频元素,在对数组进行升序排列时,我们可以利用快排,来降低时间复杂度
class Solution {
public int[] topKFrequent(int[] nums, int k) {
quickSort(0,nums.length-1,nums);
Queue<int[]>order=new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o2[1]-o1[1];
}
});
int len=0;
int num=Integer.MAX_VALUE;
for(int i=0;i<nums.length;i++){
if(nums[i]==num)
len++;
else{
if(num!=Integer.MAX_VALUE)
order.offer(new int[]{
num,len});
num=nums[i];
len=1;
}
}
order.offer(new int[]{
(int)num,len});
int[]res=new int[k];
for(int i=0;i<k;i++){
res[i]= Objects.requireNonNull(order.poll())[0];
}
return res;
}
private void quickSort(int start,int end,int[]nums){
if(start>=end)
return;
int pivot=nums[start];
int left=start;
int right=end;
while(right>left){
while(nums[right]>pivot&&right>left)
right--;
while(nums[left]<=pivot&&right>left)
left++;
Switch(nums,left,right);
}
Switch(nums,start,left);
quickSort(start,left-1,nums);
quickSort(left+1,end,nums);
}
private void Switch(int[]nums,int x,int y){
int temp=nums[x];
nums[x]=nums[y];
nums[y]=temp;
}
}
快排的时间复杂度:O(Nlog(N))(平均),O(N^2)(最坏)
快排的空间复杂度:O(log(N))(平均),O(N)(最坏)