【LeetCode】前 K 个高频元素 [M](堆)
LeetCode 元素 高频
2023-09-27 14:19:51 时间
一、题目
给你一个整数数组 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 个高频元素的集合是唯一的
二、代码
class Solution {
// 词频类
class Node {
// 数字
public int num;
// 该数字在数组中的出现次数
public int cnt;
public Node(int num) {
this.num = num;
this.cnt = 1;
}
}
// 比较器,用于构建小根堆
public class CountComparator implements Comparator<Node> {
@Override
public int compare(Node o1, Node o2) {
return o1.cnt - o2.cnt;
}
}
public int[] topKFrequent(int[] nums, int k) {
// 词频表 key:存放数组中的数字 value:存放数组中数字对应的Node
HashMap<Integer, Node> countMap = new HashMap<>();
// 遍历数字,构建词频表
for (int i = 0; i < nums.length; i++) {
if (countMap.containsKey(nums[i])) {
countMap.get(nums[i]).cnt++;
} else {
countMap.put(nums[i], new Node(nums[i]));
}
}
// 创建小根堆,根据每个数的出现次数排序,出现次数小的在堆上面
PriorityQueue<Node> heap = new PriorityQueue<>(new CountComparator());
// 遍历词频表,将每一个数字的Node加入到小根堆中,维持小根堆的大小不能超过k
// 当小根堆大小为k,如果遍历到的数字的出现次数比堆顶还要大,那么就是找到了一个更好的数字,我们将小根堆堆顶数字弹出,将这个新的数字加入到堆中
// 这样遍历完之后我们就可以找到数组中词频数在前K名的所有num了
for (Node node : countMap.values()) {
// 堆还没有满或者node.cnt小于此时的堆顶cnt,就将该数的node加入到heap中
if (heap.size() < k || heap.size() == k && node.cnt > heap.peek().cnt) {
heap.add(node);
}
// 如果上一步是加入了一个比堆顶词频大的Node,这里就要将这个最小的堆顶弹出,维持堆的大小不能超过k
if (heap.size() > k) {
heap.poll();
}
}
// 将堆中的数据都加入到答案数组中
int[] ans = new int[k];
int index = 0;
while (!heap.isEmpty()) {
ans[index++] = heap.poll().num;
}
// 返回答案
return ans;
}
}
三、解题思路
先遍历一遍弄出词频表。
小根堆按照出现次数组织,次数少的放在顶部。
如果遍历到的一个新的数,此时堆已经满了,但是新遍历到的数的词频比堆顶的词频还要大,说明这个数更好,我们将堆顶的数弹出,然后将新的数加入到堆中。
相当于我们设置了一个门槛,然后判断当前遍历到的记录能不能把门槛干掉自己进来。
整个过程维持堆的大小不超过k,这样就可以收集到前K个高频元素。
相关文章
- Leetcode: Remove Linked List Elements
- Leetcode: Jump Game
- 【Leetcode】746. 使用最小花费爬楼梯(简单)
- JS Leetcode 374. 猜数字大小 题解分析
- [LeetCode]27. 移除元素
- [LeetCode]5401. 是否所有 1 都至少相隔 k 个元素
- 187、【栈与队列】leetcode ——42. 接雨水(C++版本)
- 186、【栈与队列】leetcode ——503. 下一个更大元素 II(C++版本)
- 92、【树与二叉树】leetcode ——111. 二叉树的最小深度:层次遍历+先序DFS+后序DFS[子问题分解](C++版本)
- 87、【栈与队列】leetcode ——347. 前 K 个高频元素:优先队列(小根堆)+Hash表(C++版本)
- 64、【链表】leetcode——203. 移除链表元素(C++版本)
- 【LeetCode】130. Surrounded Regions (2 solutions)
- 【leetcode】82: 删除排序链表中的重复元素 II
- [LeetCode] 1202. Smallest String With Swaps 交换字符串中的元素
- [LeetCode] 1144. Decrease Elements To Make Array Zigzag 递减元素使数组呈锯齿状
- [LeetCode] 632. Smallest Range Covering Elements from K Lists 覆盖K个列表元素的最小区间
- [LeetCode] The Maze III 迷宫之三
- [LeetCode] Minimum Moves to Equal Array Elements II 最少移动次数使数组元素相等之二
- [LeetCode] Duplicate Emails 重复的邮箱
- [LeetCode] 48. Rotate Image 旋转图像
- Leetcode——16. 3Sum Closest
- leetcode 34. Find First and Last Position of Element in Sorted Array 在排序数组中查找元素的第一个和最后一个位置(中等)
- leetcode算法217.存在重复元素
- leetcode算法83.删除排序链表中的重复元素