难度:中等
题目:
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
-
1 <= nums.length <= 105 -
k的取值范围是[1, 数组中不相同的元素的个数] -
题目数据保证答案唯一,换句话说,数组中前
k个高频元素的集合是唯一的
**进阶:**你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n是数组大小。
解题思路:
对于找出出现频率前 k 高的元素的问题,可以从几个关键点来理解:
- 统计频率的必要性
问题需求:题目要求找出频率最高的 k 个元素,这就意味着我们必须知道每个元素的出现次数。
数据结构选择:使用哈希表(JavaScript中通常是对象或Map)来存储元素及其频率,是因为哈希表提供了快速的查找和更新操作,平均时间复杂度为O(1)。这对于统计大量数据的频率非常有用。 - 转换为可排序结构
排序需求:为了找出频率最高的元素,我们需要一种方式来比较元素的频率。直接在哈希表中进行排序是困难的,因为哈希表没有定义自然的顺序。
数组转换:将哈希表的键值对转换成数组,使得每个数组元素都是一个 [value, frequency] 的形式,这样就可以使用数组的排序方法。 - 排序的策略
降序排序:为了找出频率最高的元素,我们需要对元素按照频率进行降序排序。这样,数组的前端就会是频率最高的元素。
效率考虑:虽然排序的时间复杂度通常为O(n log n),但它提供了确定性的结果,而且在实践中通常足够快,特别是对于中小规模的数据集。 - 选取前k个元素
切片操作:一旦数组被排序,我们可以使用数组的切片操作来直接获取前 k 个元素。这是非常直接和高效的方法,时间复杂度为O(k)。 - 返回结果
输出格式:题目要求返回元素,而不包括它们的频率,因此在返回结果之前,我们仅提取数组元素的第一个元素(即元素的值),并将其作为一个新的数组返回。
JavaScript实现:
/** * @param {number[]} nums * @param {number} k * @return {number[]} */var topKFrequent = function(nums, k) { // 1、先声明一个map,用来存储相同的整数个数 // 2、遍历nums,然后比较相同的元素,然后添加到对应的数组中 // 3、然后再把map转为数组,再进行排序,再进行截取,再进行抽取数组中的第一项组成新的数组 let [map, len] = [new Map(), nums.length] for (let i = 0; i < len; i++) { let num = nums[i] if (map.has(num)) { map.set(num, map.get(num) + 1) } else { map.set(num, 1) } } // 这里一定要进行降序排列,所以是sort((a, b) => b[1] - a[1]) let arr = [...map.entries()].sort((a, b) => b[1] - a[1]).slice(0, k).map(item => item[0]) return arr;};