[LeetCode] 347. Top K Frequent Elements 前K个高频元素
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.
给一个非空整数数组,返回前k个频率最高的元素。k总是合理的,1 ≤k1 ≤独立元素的数量。要求算法时间复杂度必须优于O(n log n),n是数组长度。
解法1: 桶排序Bucket Sort, Time: O(n), Space: O(n)
1. 遍历数组nums,利用Hash map统计每个数字出现的次数。
2. 遍历map,初始化一个行数为len(nums) + 1的二维数组,将出现次数为i ( i∈[1, n] )的所有数字加到第i行。
3. 逆序遍历二维数组(从频率高的开始),将其中的前k行的元素输出。
解法2:快排Quick select, Time: O(n) ~ O(n^2), O(n) on average. Space: O(n)
解法3: 最大堆max heap,Time: O(n * log k),其中k为独立元素的个数, Space: O(n)。
1. 先用Hash map统计所有数字出现的次数。
2. 建立一个大小为k的最大堆max heap,遍历map,将出现次数和数字组成的pair推到heap中,堆顶为出现次数最多的pair,遍历结束后,把heap中的元素从堆顶一个个的取出即可。
解法4:利用Java中的TreeMap, Tree map是一个有序的key-value集合,它是通过红黑树实现的。利用map可统计,又是按key排序的。
Java: Bucket Sort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public List<Integer> topKFrequent( int [] nums, int k) { List<Integer>[] bucket = new List[nums.length + 1 ]; Map<Integer, Integer> frequencyMap = new HashMap<Integer, Integer>(); for ( int n : nums) { frequencyMap.put(n, frequencyMap.getOrDefault(n, 0 ) + 1 ); } for ( int key : frequencyMap.keySet()) { int frequency = frequencyMap.get(key); if (bucket[frequency] == null ) { bucket[frequency] = new ArrayList<>(); } bucket[frequency].add(key); } List<Integer> res = new ArrayList<>(); for ( int pos = bucket.length - 1 ; pos >= 0 && res.size() < k; pos--) { if (bucket[pos] != null ) { res.addAll(bucket[pos]); } } return res; } |
Java: Solution 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | public List<Integer> topKFrequent( int [] nums, int k) { //count the frequency for each element HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); for ( int num: nums){ if (map.containsKey(num)){ map.put(num, map.get(num)+ 1 ); } else { map.put(num, 1 ); } } //get the max frequency int max = 0 ; for (Map.Entry<Integer, Integer> entry: map.entrySet()){ max = Math.max(max, entry.getValue()); } //initialize an array of ArrayList. index is frequency, value is list of numbers ArrayList<Integer>[] arr = (ArrayList<Integer>[]) new ArrayList[max+ 1 ]; for ( int i= 1 ; i<=max; i++){ arr[i]= new ArrayList<Integer>(); } for (Map.Entry<Integer, Integer> entry: map.entrySet()){ int count = entry.getValue(); int number = entry.getKey(); arr[count].add(number); } List<Integer> result = new ArrayList<Integer>(); //add most frequent numbers to result for ( int j=max; j>= 1 ; j--){ if (arr[j].size()> 0 ){ for ( int a: arr[j]){ result.add(a); //if size==k, stop if (result.size()==k){ break ; } } } } return result; } |
Java: Heap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | class Pair{ int num; int count; public Pair( int num, int count){ this .num=num; this .count=count; } } public class Solution { public List<Integer> topKFrequent( int [] nums, int k) { //count the frequency for each element HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); for ( int num: nums){ if (map.containsKey(num)){ map.put(num, map.get(num)+ 1 ); } else { map.put(num, 1 ); } } // create a min heap PriorityQueue<Pair> queue = new PriorityQueue<Pair>( new Comparator<Pair>(){ public int compare(Pair a, Pair b){ return a.count-b.count; } }); //maintain a heap of size k. for (Map.Entry<Integer, Integer> entry: map.entrySet()){ Pair p = new Pair(entry.getKey(), entry.getValue()); queue.offer(p); if (queue.size()>k){ queue.poll(); } } //get all elements from the heap List<Integer> result = new ArrayList<Integer>(); while (queue.size()> 0 ){ result.add(queue.poll().num); } //reverse the order Collections.reverse(result); return result; } } |
Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // use treeMap. Use freqncy as the key so we can get all freqencies in order public class Solution { public List<Integer> topKFrequent( int [] nums, int k) { Map<Integer, Integer> map = new HashMap<>(); for ( int n: nums){ map.put(n, map.getOrDefault(n, 0 )+ 1 ); } TreeMap<Integer, List<Integer>> freqMap = new TreeMap<>(); for ( int num : map.keySet()){ int freq = map.get(num); if (!freqMap.containsKey(freq)){ freqMap.put(freq, new LinkedList<>()); } freqMap.get(freq).add(num); } List<Integer> res = new ArrayList<>(); while (res.size()<k){ Map.Entry<Integer, List<Integer>> entry = freqMap.pollLastEntry(); res.addAll(entry.getValue()); } return res; } } |
Python: Solution 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Solution( object ): def topKFrequent( self , nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ n = len (nums) cntDict = collections.defaultdict( int ) for i in nums: cntDict[i] + = 1 freqList = [[] for i in range (n + 1 )] for p in cntDict: freqList[cntDict[p]] + = p, ans = [] for p in range (n, 0 , - 1 ): ans + = freqList[p] return ans[:k] |
Python: Solution 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Solution( object ): def topKFrequent( self , nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ counts = collections.Counter(nums) buckets = [[] for _ in xrange ( len (nums) + 1 )] for i, count in counts.iteritems(): buckets[count].append(i) result = [] for i in reversed ( xrange ( len (buckets))): for j in xrange ( len (buckets[i])): result.append(buckets[i][j]) if len (result) = = k: return result return result |
Python: Quick Select Solution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | # Time: O(n) ~ O(n^2), O(n) on average. # Space: O(n) from random import randint class Solution( object ): def topKFrequent( self , nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ counts = collections.Counter(nums) p = [] for key, val in counts.iteritems(): p.append(( - val, key)) self .kthElement(p, k) result = [] for i in xrange (k): result.append(p[i][ 1 ]) return result def kthElement( self , nums, k): def PartitionAroundPivot(left, right, pivot_idx, nums): pivot_value = nums[pivot_idx] new_pivot_idx = left nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] for i in xrange (left, right): if nums[i] < pivot_value: nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i] new_pivot_idx + = 1 nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right] return new_pivot_idx left, right = 0 , len (nums) - 1 while left < = right: pivot_idx = randint(left, right) new_pivot_idx = PartitionAroundPivot(left, right, pivot_idx, nums) if new_pivot_idx = = k - 1 : return elif new_pivot_idx > k - 1 : right = new_pivot_idx - 1 else : # new_pivot_idx < k - 1. left = new_pivot_idx + 1 |
Python: Heap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import collections import heapq class Solution( object ): def topKFrequent( self , nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ counts = collections.Counter(nums) heap = [] for key, cnt in counts.items(): if len (heap) < k: heapq.heappush(heap, (cnt, key)) else : if heap[ 0 ][ 0 ] < cnt: heapq.heappop(heap) heapq.heappush(heap, (cnt, key)) return [x[ 1 ] for x in heap] |
Python: Solution 2, most_common实现了heapq(堆)模块
1 2 3 4 5 6 7 8 9 | class Solution( object ): def topKFrequent( self , nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ c = collections.Counter(nums) return [x[ 0 ] for x in c.most_common(k)] |
Python: Solution 2
1 2 3 4 5 6 7 8 | class Solution3( object ): def topKFrequent( self , nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ return [key for key, _ in collections.Counter(nums).most_common(k)] |
C++: Solutoin 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Solution { public : vector< int > topKFrequent(vector< int >& nums, int k) { unordered_map< int , int > m; vector<vector< int >> bucket(nums.size() + 1); vector< int > res; for ( auto a : nums) ++m[a]; for ( auto it : m) { bucket[it.second].push_back(it.first); } for ( int i = nums.size(); i >= 0; --i) { for ( int j = 0; j < bucket[i].size(); ++j) { res.push_back(bucket[i][j]); if (res.size() == k) return res; } } return res; } }; |
C++: Solution 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Solution { public : vector< int > topKFrequent(vector< int >& nums, int k) { unordered_map< int , int > m; priority_queue<pair< int , int >> q; vector< int > res; for ( auto a : nums) ++m[a]; for ( auto it : m) q.push({it.second, it.first}); for ( int i = 0; i < k; ++i) { res.push_back(q.top().second); q.pop(); } return res; } }; |
类似题目:
[LeetCode] 215. Kth Largest Element in an Array 数组中第k大的元素
[LeetCode] 192. Word Frequency 词频
[LeetCode] 692. Top K Frequent Words 前K个高频单词
All LeetCode Questions List 题目汇总
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架