题面
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出:[1,2]
示例 2:
输入: nums = [1], k = 1
输出:[1]
示例 3:
输入: nums = [1,2,1,2,1,2,3,1,3,2], k = 2
输出:[1,2]
提示:
1 <= nums.length <= 105-104 <= nums[i] <= 104k的取值范围是[1, 数组中不相同的元素的个数]- 题目数据保证答案唯一,换句话说,数组中前
k个高频元素的集合是唯一的
进阶: 你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小
分析
-
显然,统计频次之后,可以使用排序,得到频次前 k 大的元素,其时间复杂度为
-
如何优化?可以用堆来实现,而堆排序的规则就是每个数字所出现的频率
-
代码如下
class Solution { public: vector<int> topKFrequent(vector<int>& nums, int k) { unordered_map<int, int> freq_map; for (int num : nums) { freq_map[num]++; } // 定义小顶堆(优先队列),排序规则:频率小的优先出队 // 堆中存储pair<频率,元素>,默认按第一个元素降序,所以用greater反转成升序 priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> min_heap; // 步骤3:遍历频率表,维护大小为k的小顶堆 for (auto& pair : freq_map) { int num = pair.first; int freq = pair.second; if (min_heap.size() < k) { // 堆未满,直接入堆 min_heap.push({freq, num}); } else { // 堆已满,若当前频率 > 堆顶频率,替换堆顶 if (freq > min_heap.top().first) { min_heap.pop(); min_heap.push({freq, num}); } } } // 步骤4:提取堆中的元素(前k高频) vector<int> result; while (!min_heap.empty()) { result.push_back(min_heap.top().second); min_heap.pop(); } // 可选:反转结果(堆是小顶堆,结果是按频率升序,反转后为降序) // reverse(result.begin(), result.end()); return result; } }; -
上述方法的时间复杂度为 ,k 为堆的大小,显然当 k 比较大时,时间复杂度会比较高
-
如何进一步优化?可以对这些频次进行桶排序,相同频次的元素落入一个桶中,同一个桶内的元素出现次数相同,无需对桶内元素排序
-
设出现次数最大值为 maxCount,可以创建一个 maxCount+1 大小的数组 buckets,每个 buckets[c] 都对应一个列表,存储出现次数为 c 的元素列表
-
这样,可以倒序遍历 buckets,将 buckets[c] 中的元素加到答案中,一旦答案长度等于 k,就立刻返回答案
-
代码实现
class Solution { public: vector<int> topKFrequent(vector<int>& nums, int k) { // 第一步:统计每个元素的出现次数 unordered_map<int, int> cnt; int max_cnt = 0; for (int x : nums) { cnt[x]++; max_cnt = max(max_cnt, cnt[x]); } // 第二步:把出现次数相同的元素,放到同一个桶中 vector<vector<int>> buckets(max_cnt + 1); for (auto& [x, c] : cnt) { buckets[c].push_back(x); } // 第三步:倒序遍历 buckets,把出现次数前 k 大的元素加入答案 vector<int> ans; // 注意题目保证答案唯一,一定会出现某次 insert 后 ans.size() 恰好等于 k 的情况 for (int i = max_cnt; i >= 0 && ans.size() < k; i--) { ans.insert(ans.end(), buckets[i].begin(), buckets[i].end()); } return ans; } };
这篇文档有帮助吗?