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.
- It's guaranteed that the answer is unique, in other words the set of the top k frequent elements is unique.
- You can return the answer in any order.
前K个高频元素。题意是给一个非空数组,请返回前K个高频元素。前K个XX的题型思路大多不是pq就是bucket sort。题目要求时间复杂度必须优于O(nlogn)。
因为题目有时间复杂度的要求所以只能是bucket sort桶排序的思想做。这题Java的时间复杂度稍稍优于JS,是因为实现方式的不同导致。
Java时间O(n),JS时间O(nlogn)
空间O(n)
解释一下思路,既然是桶排序,所以需要将出现频率一样的元素放到同一个桶里面,所以这里会用到一个hashmap记录数字和他们各自出现频率(key:value)。接着就需要根据频率大小,挑出前K个频率最大的元素。在JS里面,map是可以根据value排序的(21行),排序完之后,可以根据排序结果,再反过来挑出前K个key(24行)。因为21行用到了快排quick sort,所以时间复杂度至少为O(nlogn)。
JavaScript实现
1 /** 2 * @param {number[]} nums 3 * @param {number} k 4 * @return {number[]} 5 */ 6 var topKFrequent = function (nums, k) { 7 // corner case 8 if (!nums || !nums.length) { 9 return []; 10 }; 11 12 // normal case 13 let map = new Map(); 14 nums.forEach((item) => { 15 if (map.has(item)) { 16 map.set(item, map.get(item) + 1); 17 } else { 18 map.set(item, 1); 19 } 20 }) 21 let res = [...map].sort((a, b) => b[1] - a[1]); 22 console.log(res); 23 res = res.map(item => item[0]); 24 return res.slice(0, k); 25 };
Java实现
在Java里面这一题的实现方式略有不同。依然是需要创建一个hashmap记录元素和其频率(第9行)。之后创建桶需要用到一个list,每一个index上连着一个linkedlist,记录同样频率的元素都有哪些(12行)。因为桶排序的桶是按照频率有序排列的,所以最后输出结果的时候可以按桶频率由大到小依次将桶内元素加入结果集(20行)。
1 class Solution { 2 public List<Integer> topKFrequent(int[] nums, int k) { 3 HashMap<Integer, Integer> map = new HashMap<>(); 4 for (int num : nums) { 5 map.put(num, map.getOrDefault(num, 0) + 1); 6 } 7 8 List<Integer>[] bucket = new List[nums.length + 1]; 9 for (int num : map.keySet()) { 10 int freq = map.get(num); 11 if (bucket[freq] == null) { 12 bucket[freq] = new LinkedList<>(); 13 } 14 bucket[freq].add(num); 15 } 16 17 List<Integer> res = new ArrayList<>(); 18 for (int i = bucket.length - 1; i >= 0 && res.size() < k; i--) { 19 if (bucket[i] != null) { 20 res.addAll(bucket[i]); 21 } 22 } 23 return res; 24 } 25 }
Java, new code signature updated in June 2020.
1 class Solution { 2 public int[] topKFrequent(int[] nums, int k) { 3 HashMap<Integer, Integer> map = new HashMap<>(); 4 for (int num : nums) { 5 map.put(num, map.getOrDefault(num, 0) + 1); 6 } 7 8 List<Integer>[] bucket = new List[nums.length + 1]; 9 for (int num : map.keySet()) { 10 int freq = map.get(num); 11 if (bucket[freq] == null) { 12 bucket[freq] = new LinkedList<>(); 13 } 14 bucket[freq].add(num); 15 } 16 17 int[] res = new int[k]; 18 int cur = 0; 19 for (int i = bucket.length - 1; i > 0; i--) { 20 if (bucket[i] == null) { 21 continue; 22 } 23 for (int n : bucket[i]) { 24 res[cur] = n; 25 cur++; 26 if (cur == k) { 27 return res; 28 } 29 } 30 } 31 return res; 32 } 33 }
Java Priority Queue 实现 - 时间复杂度O(nlogn)
1 class Solution { 2 public int[] topKFrequent(int[] nums, int k) { 3 HashMap<Integer, Integer> map = new HashMap<>(); 4 for (int num : nums) { 5 map.put(num, map.getOrDefault(num, 0) + 1); 6 } 7 8 PriorityQueue<Map.Entry<Integer, Integer>> maxHeap = new PriorityQueue<>((a, b) -> b.getValue() - a.getValue()); 9 for (Map.Entry<Integer, Integer> entry : map.entrySet()) { 10 maxHeap.offer(entry); 11 } 12 int[] res = new int[k]; 13 for (int i = 0; i < k; i++) { 14 res[i] = maxHeap.poll().getKey(); 15 } 16 return res; 17 } 18 }