leetcode
leetcode 2951 ~ 3000
前 K 个高频元素

前 K 个高频元素

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 28 ms, 内存: 19.3 MB


/*
 * 思路:
 * 1. 使用Stream和Collectors来统计每个数字的频率。
 * 2. 使用Stream来获取频率最高的k个元素。
 * 3. 使用Stream和Collectors将结果转换为数组。
 */
import java.util.*;
import java.util.stream.Collectors;

public class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        // 使用Stream统计频率
        Map<Integer, Long> frequencyMap = Arrays.stream(nums)
            .boxed()
            .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
        // 使用Stream获取前k个频率最高的元素
        List<Integer> topK = frequencyMap.entrySet().stream()
            .sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
            .limit(k)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
        // 转换为数组并返回
        return topK.stream().mapToInt(Integer::intValue).toArray();
    }
}

解释

方法:

该题解的方法是使用哈希表和最小堆。首先,使用哈希表来统计每个元素的频率。然后,使用最小堆来维护当前频率最高的前k个元素。遍历哈希表中的每个元素及其频率,将其推入堆中。如果堆的大小超过k,就弹出堆顶元素,保证堆的大小始终为k。最后,从堆中取出所有元素,这些就是出现频率最高的前k个元素。

时间复杂度:

O(n log k)

空间复杂度:

O(u + k)

代码细节讲解

🦆
为什么选择使用最小堆而不是最大堆来处理前k个高频元素的问题?
使用最小堆而不是最大堆有助于有效地管理前k个最高频的元素。在这种方法中,堆的大小固定为k,并且堆顶元素是堆中频率最小的元素。当新的元素频率比堆顶元素的频率大时,将堆顶元素替换出来,新元素入堆,这样可以保证堆中始终存储的是最高的k个频率的元素。如果使用最大堆,则需要维护所有元素的堆,并且频繁地进行插入和删除操作,这在时间复杂度上通常不如使用固定大小的最小堆效率高。
🦆
堆中元素超过k时弹出堆顶元素的逻辑是怎样保证最终堆中仍然是最频繁的k个元素?
在使用最小堆处理时,堆的大小是固定为k。当堆中的元素数量超过k时,意味着新加入的元素频率高于堆顶的元素(频率最低的元素)。因此,移除堆顶元素,然后将新元素添加进堆中,可以确保堆中始终保留的是频率最高的k个元素。这种方法通过始终淘汰频率最低的元素,保证了在任何时候堆内都是目前遇到的最高频的k个元素。
🦆
在最小堆中,元素是按照频率还是元素值来排序?如果按频率排序,那么在频率相同的情况下如何处理?
在最小堆中,元素是按照频率来排序的。堆中每个元素是一个二元组,其中第一个元素是频率,第二个元素是实际的数组值。当两个元素频率相同时,堆会根据元素值(二元组的第二个元素)来进一步排序,以保持一致的处理逻辑。这意味着如果两个元素频率相同,则它们在堆中的顺序将由它们的值决定。

相关问题