leetcode 347. Top K Frequent Elements

博客围绕求非空整数数组中k个最频繁元素的问题展开,介绍三种思路。思路一是将数组元素按频率从高到低排序后取前k个;思路二用最小堆,保留频率最大的k个数,若新元素频率更大则替换堆顶;思路三是桶排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

Given a non-empty array of integers, return the k most frequent elements.

Example 1:

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2:

Input: nums = [1], k = 1
Output: [1]

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.

本文思路来源:https://www.cnblogs.com/xugenpeng/p/9950007.html

这篇博客总结的很好,所以这里只做了一下搬运工。

思路一

将数组元素按照频率有高到低排序,然后取出前K个。

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        //统计元素频率
        Map<Integer,Integer> map=new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        //对元素按照频率进行排序
        List<Map.Entry<Integer,Integer>> list=new ArrayList<>(map.entrySet());
        Collections.sort(list,new Comparator<Map.Entry<Integer,Integer>>(){
            @Override
            public int compare(Map.Entry<Integer,Integer> o1,Map.Entry<Integer,Integer> o2){
                return o2.getValue()-o1.getValue();
            }
        });
        //取出前K个元素
        int count=0;
        List<Integer> ret=new ArrayList<>();
        for(Map.Entry<Integer,Integer> entry:list){
            ret.add(entry.getKey());
            count++;
            if(count>=k){
                break;
            }
        }
        return ret;        
        
    }
}

思路二:最小堆

这里我们可以联系到之前做过的剑指offer中最小的K个数的方法,对于海量数据中最小的K个数选用最大堆来保存。

这里我们选取最小堆,堆中保留频率最大的K 个数,堆顶元素最小,若新来的元素比这个最小的频率大,则替换堆顶元素。

import java.util.*;
class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        //统计元素频率
        Map<Integer,Integer> map=new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        //遍历map,用最小堆保存频率前k大的元素
        PriorityQueue<Integer> minQueue=new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return map.get(o1)-map.get(o2);
            }
        });
        for (Integer key:map.keySet()){
            if(minQueue.size()<k){
                minQueue.add(key);
            }else if(map.get(key)>map.get(minQueue.peek())){
                //新来的元素频率大于堆顶元素的频率
                minQueue.remove();
                minQueue.add(key);
            }
        }
        //取出最小堆中的元素
        List<Integer> ret=new ArrayList<>();
        while(!minQueue.isEmpty()){
            ret.add(minQueue.remove());// 从此队列中移除指定元素的单个实例(如果存在)。
        }
        return ret;
    }
}

思路三:桶排序

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        //统计元素频次
        Map<Integer,Integer> map=new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        //桶排序
        List<Integer>[] bucket=new List[nums.length+1];
        for(Integer key:map.keySet()){
            int freq=map.get(key);
            if(bucket[freq]==null){
                bucket[freq]=new ArrayList<>();
            }
            bucket[freq].add(key);
        }
        //按照频数从高到低取出元素
        List<Integer> ret=new ArrayList<>();
        for(int i=nums.length;i>=0&&ret.size()<k;i--){
            if(bucket[i]!=null){
                ret.addAll(bucket[i]);
            }
        }
        return ret;        
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值