问题描述
给出一个数组和一个数字k,要求找出数组中数字出现频率最高的k个数字。如果按照出现频率从高到低取数字时,发现在某个频率有 m 个相同的数字,在该频率前面共有 n 个数字,且 n + m > k,则从m个数字中任意取 k - n个数字,这 k - n个数字无顺序要求,也无特定数字要求。
此题要求时间复杂度小于O(nlog n),其中 n 是数组的长度
样例输入输出
输入:nums = [][1,1,1,2,2,3] [1,1,1,2,2,3] , k = 2
输出:[1,2]
输入:nums = [1,1,1,3,3,3,2,2,2] , k = 2
输出:[1,2]或者[1,3]或者[2,3]。不能输出[1,2,3]
问题解法
此解法主要参考**https://leetcode.com/problems/top-k-frequent-elements/discuss/81635/3-Java-Solution-using-Array-MaxHeap-TreeMap**
主要过程如下
- 先遍历数组,找出每个数字出现的次数,存放在map中
- 遍历map,用一个List数组来存放map中的数组,其中数组的下标是map的value值,表示数字出现的次数,数组下标对应的元素是一个List列表,存放数组中数字出现次数是这个下标值的数字。假设输入数组是[3,4,2,7,7,7,1,1,1,5,5,5,8,8,8,9,9,9,9,9],则构造的数组如下图所示,数组下标5的位置存放数字9,说明9出现的次数是5次,数组下标位置3存放的数字列表是[7,1,5,8],说明数字7、1、5、8出现的次数是3,数组下标位置1存放的数字列表是[3,4,2],说明数字3、4、2出现的次数是1,数组下标位置4、6没有存放数字,说明没有数字出现的次数是4次或6次。
- 对第二步骤构造的数组,从后向前遍历,依次取出k个数字作为结果返回。例如以上图为例,假设k = 2,则返回[9,7](数字9出现5次,数字7出现3此,当然也可以返回[9,1]或其他等价的结果),假设k = 1,则返回[9],假设k = 5,则返回[9,7,1,5,8](当然,也可以返回[9,7,5,1,8]或其他等价的结果)
整个过程时间复杂度为O(n),低于题目的要求O(nlog n)
代码如下
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| import java.util.Map.Entry; class Solution { public List<Integer> topKFrequent(int[] nums, int k) { Map<Integer, Integer> numsMap = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int numCount = numsMap.getOrDefault(nums[i], 0) + 1; numsMap.put(nums[i], numCount); } List<Integer>[] numCountsBucket = new List[nums.length + 1]; for (Entry<Integer, Integer> entry : numsMap.entrySet()) { int num = entry.getKey(); int count = entry.getValue(); List<Integer> numList = numCountsBucket[count]; if (numList == null) { numList = new ArrayList<>(); numList.add(num); numCountsBucket[count] = numList; } else { numList.add(num); } } List<Integer> result = new ArrayList<>(); for (int i = numCountsBucket.length - 1; i >= 0; i--) { List<Integer> numList = numCountsBucket[i]; if (numList != null) { result.addAll(numList); k -= numList.size(); } if (k == 0) { break; } else if (k < 0) { while (k < 0) { result.remove(result.size() - 1); k++; } break; } } return result; } }
|
参考资料
https://leetcode.com/problems/top-k-frequent-elements/discuss/81635/3-Java-Solution-using-Array-MaxHeap-TreeMap