Skip to content

题目链接 · 灵神原题解(署名来源)

第一步

既然答案与元素的出现次数有关,那么先用一个哈希表 cnt 统计每个元素的出现次数。哈希表的 key 是元素值,value 是 key 在数组中的出现次数。

此时问题变成:

  • 返回一个列表,包含前 k 大的出现次数对应的元素值。

第二步

把出现次数相同的元素,放到同一个桶中。同一个桶内的元素出现次数相同,无需对桶内元素排序。

设出现次数的最大值为 maxCnt。创建一个大小为 maxCnt+1 的列表 buckets,其中 buckets[c] 存储出现次数为 c 的元素。(每个 buckets[c] 都是一个列表)

注意 maxCntn,这保证了时间复杂度是 O(n) 的。

遍历 cnt,把出现次数为 c 的元素 x 添加到 buckets[c] 中。

第三步

倒序遍历 buckets,把 buckets[c] 中的元素加到答案中。

一旦答案的长度等于 k,就立刻返回答案。

注 1:题目保证答案唯一,所以一定会出现答案长度恰好等于 k 的情况。

注 2:可以按任意顺序返回答案。比如示例 1 返回 [1,2] 还是 [2,1] 都是正确的。

python
class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        # 第一步:统计每个元素的出现次数
        cnt = Counter(nums)
        max_cnt = max(cnt.values())

        # 第二步:把出现次数相同的元素,放到同一个桶中
        buckets = [[] for _ in range(max_cnt + 1)]  # 也可以用 defaultdict(list)
        for x, c in cnt.items():
            buckets[c].append(x)

        # 第三步:倒序遍历 buckets,把出现次数前 k 大的元素加入答案
        ans = []
        for bucket in reversed(buckets):
            ans += bucket
            # 注意题目保证答案唯一,一定会出现恰好等于 k 的情况
            if len(ans) == k:
                return ans
cpp
// C++ 版待补充
cpp
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; ans.size() < k; i--) {
            ans.insert(ans.end(), buckets[i].begin(), buckets[i].end());
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n),其中 nnums 的长度。
  • 空间复杂度:O(n)

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

本文整理自灵茶山艾府(endlesscheng)的公开内容,仅供个人学习使用

本站仅供个人学习使用,请勿外传