排序算法 桶排序 347. Top K Frequent Elements

该博客介绍了如何在给定整数数组中找出出现频率最高的k个元素。通过桶排序和哈希映射的方法,可以在O(n)的时间复杂度内解决此问题。首先,创建一个哈希表记录每个数的出现次数,然后根据出现次数构建桶,最后从高频率的桶开始收集元素,直至得到k个最频繁的元素。这种方法适用于数据分布相对均匀的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
Example 2:
Input: nums = [1], k = 1
Output: [1]
Constraints:
1 <= nums.length <= 105
k is in the range [1, the number of unique elements in the array].
It is guaranteed that the answer is unique.

桶排序是将数据划分出桶,放入有序的桶内,每个桶内分别进行排序,最后合并
桶排序的时间复杂度仅是On,非常快,但使用条件比较严格,首先数据必须能划分出桶来(比如数极差很大,接近INT_MAX,这时建有序桶就会消耗很大)
其次数据需要尽量分布均匀,不然桶排序相当于在一两个桶内排序,没意义。
讲解 https://blog.csdn.net/zihonggege/article/details/104781491

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int,int> map;
        int max_count = 0;
        //建立每个数与出现次数的索引,并记录最多的出现次数
        for(int num : nums){
            max_count = max(max_count, ++map[num]);
        }
        //从0到max_count,每个出现次数建立一个桶
        vector<vector<int>> buckets(max_count+1);
        for(auto it : map){
            buckets[it.second].push_back(it.first);
        }
        vector<int> res;
        for(int i = buckets.size()-1; i >= 0 && res.size() < k; i--){
            for(int num : buckets[i]){
                res.push_back(num);
            }
        }
        return res;
    }
  
};
### C++ 实现 Top-K 算法 Top-K 问题是常见的算法问题之一,通常用于从大量数据中找到排名靠前的 K 个元素。下面是一个完整的 C++ 示例代码及其解释。 #### 示例代码 ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; // 定义比较函数,使得 priority_queue 成为最小堆 struct Compare { bool operator()(const pair<int, int>& a, const pair<int, int>& b) { return a.second < b.second; // 按照频率从小到大排序 } }; vector<int> topKFrequentElements(vector<int>& nums, int k) { unordered_map<int, int> frequencyMap; // 记录每个元素出现的次数 for (auto num : nums) { frequencyMap[num]++; } // 使用优先队列(最小堆)存储频率最高的 k 个元素 priority_queue<pair<int, int>, vector<pair<int, int>>, Compare> minHeap; for (auto& entry : frequencyMap) { minHeap.push({entry.first, entry.second}); if (minHeap.size() > k) { minHeap.pop(); // 移除堆顶元素(频率最低) } } vector<int> result; while (!minHeap.empty()) { result.push_back(minHeap.top().first); // 提取堆中的元素 minHeap.pop(); } reverse(result.begin(), result.end()); // 结果按频率降序排列 return result; } int main() { vector<int> nums = {1, 1, 1, 2, 2, 3}; int k = 2; vector<int> result = topKFrequentElements(nums, k); cout << "Top-" << k << " frequent elements: "; for (auto elem : result) { cout << elem << " "; } cout << endl; return 0; } ``` --- ### 代码详解 1. **输入准备** - 输入数组 `nums` 是待处理的数据集。 - 参数 `k` 表示需要找出的最高频次的元素数量。 2. **构建频率表** - 使用 `unordered_map<int, int>` 存储每个元素的出现次数[^1]。 - 遍历整个数组,统计每个元素的频率。 3. **使用最小堆筛选 Top-K 元素** - 创建一个自定义比较规则的小根堆(`priority_queue`),其中堆顶是最不频繁的元素。 - 遍历频率表,将元素插入堆中。如果堆的大小超过了 `k`,则弹出堆顶元素(即频率最低的元素)。 4. **提取结果** - 堆中剩余的元素就是频率最高的 `k` 个元素。 - 将这些元素依次取出并存入结果向量中。 5. **输出结果** - 输出最终的 Top-K 频繁元素列表。 --- ### 性能分析 - **时间复杂度**: - 统计频率阶段:\( O(n) \),其中 \( n \) 是数组长度。 - 构建堆阶段:每次插入或删除操作的时间复杂度为 \( O(\log{k}) \),总共最多进行 \( m \) 次(m 为不同元素的数量)。因此这一部分的时间复杂度为 \( O(m \cdot \log{k}) \)[^1]。 - 整体时间复杂度为 \( O(n + m \cdot \log{k}) \)。 - **空间复杂度**: - 主要由频率表和堆占用的空间决定,分别为 \( O(m) \) 和 \( O(k) \)。整体空间复杂度为 \( O(m + k) \)。 --- ### 示例运行 假设输入数组为 `{1, 1, 1, 2, 2, 3}`,参数 `k=2`: - 频率表为:`{1 -> 3, 2 -> 2, 3 -> 1}` - 最小堆逐步变化过程: - 插入 `(1, 3)` → 堆为 `[(1, 3)]` - 插入 `(2, 2)` → 堆为 `[(2, 2), (1, 3)]` - 插入 `(3, 1)` 并移除堆顶 `(3, 1)` → 堆为 `[(2, 2), (1, 3)]` - 最终结果为 `[1, 2]`。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值