给你一个整数数组
nums和一个整数k,请你返回其中出现频率前k高的元素。你可以按 任意顺序 返回答案。
解法1 堆排序
思路
返回频率最高的几个元素,首先需要的肯定一个频率表,所以需要先给频次计数。
接下来就是入堆了,这里使用二维数组来模拟(C++ 可以用 pair),保存数值和频次。最后将这个二维数组返回为一维即可。
代码
function topKFrequent(nums: number[], k: number): number[] {
const freqMap = new Map<number, number>();
// 1. 统计频率
for (const num of nums) {
freqMap.set(num, (freqMap.get(num) || 0) + 1);
}
// 2. 定义最小堆:存储 [num, freq] 对
const heap: [number, number][] = [];
const pushHeap = (item: [number, number]) => {
heap.push(item);
let i = heap.length - 1;
while (i > 0) {
const parent = Math.floor((i - 1) / 2);
if (heap[parent][1] <= heap[i][1]) break;
[heap[parent], heap[i]] = [heap[i], heap[parent]];
i = parent;
}
};
const popHeap = (): [number, number] => {
const top = heap[0];
const last = heap.pop()!;
if (heap.length === 0) return top;
heap[0] = last;
let i = 0;
while (true) {
let left = 2 * i + 1;
let right = 2 * i + 2;
let smallest = i;
if (left < heap.length && heap[left][1] < heap[smallest][1]) smallest = left;
if (right < heap.length && heap[right][1] < heap[smallest][1]) smallest = right;
if (smallest === i) break;
[heap[i], heap[smallest]] = [heap[smallest], heap[i]];
i = smallest;
}
return top;
};
// 3. 维护堆中只保留前 k 个频率最高的元素
for (const [num, freq] of freqMap.entries()) {
pushHeap([num, freq]);
if (heap.length > k) {
popHeap(); // 移除最小频率
}
}
return heap.map(([num]) => num);
};
时空复杂度
时间复杂度:O(n logk)
空间复杂度:O(n + k)
解法2 桶排序
思路
桶排序的思路比堆排序稍微好理解一点,就是模拟 n 个桶,每个索引为频次,然后从大的索引往小的索引遍历,如果桶里有值,那就放到结果当中。
代码
function topKFrequent(nums: number[], k: number): number[] {
const freqMap = new Map<number, number>();
// 1. 统计每个元素出现的频率
for (const num of nums) {
freqMap.set(num, (freqMap.get(num) || 0) + 1);
}
// 2. 初始化桶数组:索引为频率,值为出现这些频率的数
const buckets: number[][] = Array(nums.length + 1).fill(0).map(() => []);
for (const [num, freq] of freqMap.entries()) {
buckets[freq].push(num);
}
// 3. 从后往前遍历桶,收集频率最高的 k 个元素
const result: number[] = [];
for (let i = buckets.length - 1; i >= 0 && result.length < k; i--) {
if (buckets[i].length > 0) {
result.push(...buckets[i]);
}
}
return result.slice(0, k);
};
时空复杂度
时间复杂度:O(n)
空间复杂度:O(n)