【2024-04-30】T347_前k个高频元素

文章介绍了如何使用Java编程语言,通过map统计整数数组中元素的出现频率,并利用优先级队列(如小顶堆)找到出现频率前k高的元素。两种方法分别是根据map的value排序和基于小顶堆的实现。
摘要由CSDN通过智能技术生成

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

  • 示例 1:
    输入: nums = [1,1,1,2,2,3], k = 2
    输出: [1,2]
  • 示例 2:
    输入: nums = [1], k = 1
    输出: [1]

思路

  1. 要统计元素出现频率
  2. 对频率排序
  3. 找出前K个高频元素
    首先统计元素出现的频率,这一类的问题可以使用map来进行统计,根据map的value排序
    然后是对频率进行排序,这里我们可以使用一种 容器适配器就是==优先级队列==。

方法一: 根据map的value排序

1.将 nums 的数字和频次放入map中

我们将 key 设置为 num 中出现的数字, value 设置为出现的频次.
 map.getOrDefault(num, 0) 是一个Map接口的方法调用,用于获取给定键 num 对应的值,如果键不存在,则返回默认值 0

HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {  
    map.put(num, map.getOrDefault(num, 0) + 1);  
}
2.将Map的键值对转换为List

map.entrySet() 是 Map 接口中的一个方法,它返回一个包含 Map 中所有键值对(Entry)的集合。具体来说,它返回一个 Set 集合,该集合中的每个元素都是一个 Map.Entry 对象,表示 Map 中的一个键值对。
每个 Map.Entry 对象都包含两个方法:getKey() 和 getValue(),用于获取键和对应的值。

List<Map.Entry<Integer, Integer>> entryList = new ArrayList<>(map.entrySet());
3.使用ComparatorList进行排序

Comparator.reverseOrder()按值从大到小排序

entryList.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));
4.遍历排序后的List, 根据value排序
int cnt = 0;  
for(Map.Entry<Integer, Integer> entry : entryList){  
    res[cnt++] = entry.getKey();  
    System.out.println(entry.getKey() + " -> " + entry.getValue());  
    if (cnt == k ) break;  
}
5.最终代码
/**  
 * 方法一: 根据 Map 的 value 进行排序  
 * @param nums  
 * @param k  
 * @return  
 */  
public int[] topKFrequent(int[] nums, int k) {  
    HashMap<Integer, Integer> map = new HashMap<>();  
    int[] res = new int[k];  
  
    for (int num : nums) {  
        map.put(num, map.getOrDefault(num, 0) + 1);  
    }  
  
    // 1.将Map的键值对转换为List  
    List<Map.Entry<Integer, Integer>> entryList = new ArrayList<>(map.entrySet());  
    // 2.使用Comparator对List进行排序  
    // Comparator.reverseOrder()按值从大到小排序  
    entryList.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));  
  
    // 3.遍历排序后的List  
    int cnt = 0;  
    for(Map.Entry<Integer, Integer> entry : entryList){  
        res[cnt++] = entry.getKey();  
        System.out.println(entry.getKey() + " -> " + entry.getValue());  
        if (cnt == k ) break;  
    }  
      
    return res;  
}

方法二: 基于小顶堆

1.将 nums 的数字和频次放入map中
HashMap<Integer, Integer> map = new HashMap<>();  
for (int num : nums) {  
    map.put(num, map.getOrDefault(num, 0) + 1);  
}
2.设置优先级队列

优先级队列(Priority Queue)是一种特殊的队列数据结构,它可以根据元素的优先级进行排序和访问。具体可见

// (Comparator.comparingInt(o -> o[1]) 将按照数组中索引为1的元素的大小对二维数组进行排序  
PriorityQueue<int[]> pq = new PriorityQueue<>((Comparator.comparingInt(o -> o[1])));
3.获取键值对, 插入优先级队列
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {  
    // 获取 k-v    int[] tmp = new int[2];  
    tmp[0] = entry.getKey();  
    tmp[1] = entry.getValue();  
    // 进入优先队列  
    pq.offer(tmp);  
    // 根据小顶堆进行排序, 仅有 k 个元素在堆里面, 多到的需要出队  
    if (pq.size() > k){  
        pq.poll();  
    }  
}
4.通过优先级队列构造k个节点的小顶堆完成, 取出元素即可
for (int i = 0; i < k; i++) {  
    int[] tmp = pq.poll();  
    res[i] = tmp[0];  
    System.out.println("[" + tmp[0] + tmp[1] + "]");  
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值