前 K 个高频元素

题目

给你一个整数数组 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 个高频元素的集合是唯一的

解题思路:

对于找出出现频率前 k 高的元素的问题,可以从几个关键点来理解:

  1. 统计频率的必要性
    问题需求:题目要求找出频率最高的 k 个元素,这就意味着我们必须知道每个元素的出现次数。
    数据结构选择:使用哈希表(JavaScript中通常是对象或Map)来存储元素及其频率,是因为哈希表提供了快速的查找和更新操作,平均时间复杂度为O(1)。这对于统计大量数据的频率非常有用。
  2. 转换为可排序结构
    排序需求:为了找出频率最高的元素,我们需要一种方式来比较元素的频率。直接在哈希表中进行排序是困难的,因为哈希表没有定义自然的顺序。
    数组转换:将哈希表的键值对转换成数组,使得每个数组元素都是一个 [value, frequency] 的形式,这样就可以使用数组的排序方法。
  3. 排序的策略
    降序排序:为了找出频率最高的元素,我们需要对元素按照频率进行降序排序。这样,数组的前端就会是频率最高的元素。
    效率考虑:虽然排序的时间复杂度通常为O(n log n),但它提供了确定性的结果,而且在实践中通常足够快,特别是对于中小规模的数据集。
  4. 选取前k个元素
    切片操作:一旦数组被排序,我们可以使用数组的切片操作来直接获取前 k 个元素。这是非常直接和高效的方法,时间复杂度为O(k)。
  5. 返回结果
    输出格式:题目要求返回元素,而不包括它们的频率,因此在返回结果之前,我们仅提取数组元素的第一个元素(即元素的值),并将其作为一个新的数组返回。

这个问题可以通过几个步骤来解决:

  1. 统计元素出现的频率:遍历数组 nums,使用哈希表(JavaScript中的对象或Map)来统计每个元素出现的次数。
  2. 将频率信息转换成可排序的结构:将哈希表的键值对转换成一个数组,每个数组元素是一个 [value, frequency] 形式的数组,其中 value 是原数组中的元素,frequency 是它的出现次数。
  3. 根据频率排序:对上述数组按照频率进行排序。由于我们需要频率最高的元素,可以使用降序排序。
  4. 选取前k个元素:从排序后的数组中取出前 k 个元素。
  5. 返回结果:返回步骤4中获取的元素列表。
    function topKFrequent(nums, k) {
        // 第一步:统计每个元素的频率。
        // 创建一个对象来保存每个数字的出现次数。
        const frequencyMap = {};
        nums.forEach(num => {
            // 如果数字已经在频率图中,增加其计数;否则,初始化为1。
            frequencyMap[num] = (frequencyMap[num] || 0) + 1;
        });
    
        // 第二步:将频率图转换为一个包含[element, frequency]对的数组。
        // 使用Object.entries将对象转换为键值对数组,然后映射为包含数字和频率的数组。
        const freqArray = Object.entries(frequencyMap).map(([num, freq]) => [parseInt(num), freq]);
    
        // 第三步:根据频率对数组进行降序排序。
        // 使用sort函数,并提供一个比较函数来按频率降序排列。
        freqArray.sort((a, b) => b[1] - a[1]);
    
        // 第四步:根据频率提取前k个元素。
        // 切片数组以获取前k个元素,然后映射回仅包含元素的数组。
        const topK = freqArray.slice(0, k).map(item => item[0]);
    
        // 第五步:返回结果。
        // 最终返回包含前k个最高频率元素的数组。
        return topK;
    }
    
    // 测试函数
    // const numsExample = [1, 1, 1, 2, 2, 3];
    // const kExample = 2;
    // console.log(topKFrequent(numsExample, kExample)); // 预期输出: [1, 2]

涉及到的小知识点: 

1.“||”符号:

  • 逻辑或运算符‌:‌在C语言等编程语言中,‌“||”表示逻辑“或”运算符,‌用于判断多个条件中是否至少有一个成立。‌当任何一个操作数为真时,‌结果为真;‌只有当两个操作数都为假时,‌结果才为假。‌具有短路求值特性,‌即如果第一个操作数为真,‌则不计算第二个操作数‌。‌

2. Object.entries方法‌:返回对象键值对数组

即:使用Object.entries(frequencyMap)获取频率图frequencyMap的所有键值对,‌每个键值对是一个包含键和值的数组。‌

3.使用sort方法排序freqArray:

即:‌排序依据‌:‌数组中元素的第二个值(‌即频率)‌;‌排序方式‌:‌降序排列

4.‌slice方法:用于提取原数组的一部分,‌返回一个新数组,‌原数组不会被修改。‌

5.‌map方法:map方法是JavaScript中的一种数组方法,‌用于遍历数组并返回一个新数组,‌该数组的元素为原始数组元素调用函数处理后的值。‌

  • 23
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值