主题
第一步
既然答案与元素的出现次数有关,那么先用一个哈希表
此时问题变成:
- 返回一个列表,包含前
大的出现次数对应的元素值。
第二步
把出现次数相同的元素,放到同一个桶中。同一个桶内的元素出现次数相同,无需对桶内元素排序。
设出现次数的最大值为
注意
,这保证了时间复杂度是 的。
遍历
第三步
倒序遍历
一旦答案的长度等于
注 1:题目保证答案唯一,所以一定会出现答案长度恰好等于
的情况。 注 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 anscpp
// 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;
}
};复杂度分析
- 时间复杂度:
,其中 是 的长度。 - 空间复杂度:
。
分类题单
- 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
- 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
- 单调栈(基础/矩形面积/贡献法/最小字典序)
- 网格图(DFS/BFS/综合应用)
- 位运算(基础/性质/拆位/试填/恒等式/思维)
- 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
- 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
- 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
- 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
- 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
- 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
- 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)
欢迎关注 B站@灵茶山艾府