Tag
【哈希表】【类设计】【2024-03-21】
题目来源
解题思路
方法一:一个哈希表超时
思路
看到这个题目朴素的思想是使用一个哈希表,记录 number
的数量。每增加一个 number
就将哈希表中键值对的值 +1
。
从数据结构中删除一个 number
,需要先判断哈希表中是否存在 number
,如果存在,则将对应的值 -1
。通过哈希表中值是否为 0
来判断数据结构中不含有 number
,如果某个 number
对应的值为 0
,则 number
不存在于数据结构中。
判断数据结构中是否存在出现 frequency
次的数字时,直接枚举哈希表中的所有值,如果有某个键对应的值等于 frequency
,则直接返回 true
,否则返回 false
。但是,枚举的方法有风险,容易造成时间复杂度超时。如果查询次数与 number
的频次均达到
1
0
5
10^5
105,必超时。果不其然,最后几个测试用例就爆了。
代码就不贴出来了。
方法二:两个哈希表
思路
方法一超时的原因在于枚举查找指定的频次,再增加一个哈希表 freq_cnt
来统计频次出现的次数。
哈希表我们用数组来实现。
因为 1 ≤ n u m b e r ≤ 1 0 5 1 \le number \le 10^5 1≤number≤105,所以数组的长度可以限定为 1 0 5 + 1 10^5+1 105+1。
对于元素 number
的增加和删除操作,流程如下:
- 先减少
cnts[number]
在freq_cnt
中的计数; - 再更新
cnts[number]
; - 最后,增加
cnts[number]
在freq_cnt
中的计数。
实现代码
class FrequencyTracker {
public:
FrequencyTracker(): cnts(N), freq_cnt(N) {}
void add(int number) {
--freq_cnt[cnts[number]];
++cnts[number];
++freq_cnt[cnts[number]];
}
void deleteOne(int number) {
if (cnts[number] == 0) return;
--freq_cnt[cnts[number]];
--cnts[number];
++freq_cnt[cnts[number]];
}
bool hasFrequency(int frequency) {
return freq_cnt[frequency];
}
private:
static constexpr int N = 100001;
vector<int> cnts, freq_cnt;
};
复杂度分析
时间复杂度: O ( q ) O(q) O(q), q q q 是查询次数。所有单词操作的复杂度为 O ( 1 ) O(1) O(1)。
空间复杂度: O ( m ) O(m) O(m), m m m 是值域的范围,本题中等于 1 0 5 10^5 105。
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。