题目
432.全 O(1) 的数据结构
题目大意
请你设计一个用于存储字符串计数的数据结构,并能够返回计数最小和最大的字符串。
实现 AllOne
类:
AllOne()
初始化数据结构的对象。inc(String key)
字符串key
的计数增加1
。如果数据结构中尚不存在key
,那么插入计数为1
的key
。dec(String key)
字符串key
的计数减少1
。如果key
的计数在减少后为0
,那么需要将这个key
从数据结构中删除。测试用例保证:在减少计数前,key
存在于数据结构中。getMaxKey()
返回任意一个计数最大的字符串。如果没有元素存在,返回一个空字符串""
。getMinKey()
返回任意一个计数最小的字符串。如果没有元素存在,返回一个空字符串""
。
样例
数据规模
提示:
1 <= key.length <= 10
key
由小写英文字母组成- 测试用例保证:在每次调用
dec
时,数据结构中总存在key
- 最多调用
inc
、dec
、getMaxKey
和getMinKey
方法 5 ∗ 1 0 4 5 * 10^4 5∗104 次
思路
观察数据规模:最多调用 inc
、dec
、getMaxKey
和 getMinKey
方法
5
∗
1
0
4
5 * 10^4
5∗104 次。那么实际上设计出
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)的算法就可以完成本题(当然如果需要更优秀的算法,比如十字链表,还请查看别的博客)。
考虑使用优先队列:使用大根堆和小根堆保存(数量, 字符串)的映射,用数量作为排序的键。
- 增加和删除的时候,把当前的新版本的(数量,字符串)放入队列中。这样队列中保存的就是新版本和老版本的(数量, 字符串)。
- 问的时候,进行懒删除: 如果当前的队头元素不是最新的元素(
mp[s]==num(auto [num,s]=q.top())
)就删除;如果该元素是最新的,就直接使用,并且不删除。 - 如果数量等于 0 0 0,就不用放入队列中;否则需要再访问的时候,判断是否为0。
代码
// short int long float double bool char string void
// array vector stack queue auto const operator
// class public private static friend extern
// sizeof new delete return cout cin memset malloc
// relloc size length memset malloc relloc size length
// for while if else switch case continue break system
// endl reverse sort swap substr begin end iterator
// namespace include define NULL nullptr exit equals
// index col row arr err left right ans res vec que sta
// state flag ch str max min default charray std
// maxn minn INT_MAX INT_MIN push_back insert
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>PII;
typedef pair<int, string>PIS;
const int maxn=1e6+50;//注意修改大小
long long read(){long long x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;}
ll qpow(ll x,ll q,ll Mod){ll ans=1;while(q){if(q&1)ans=ans*x%Mod;q>>=1;x=(x*x)%Mod;}return ans%Mod;}
class AllOne {
public:
unordered_map<string,int>mp;
priority_queue<PIS,vector<PIS>,greater<PIS>>lq;
priority_queue<PIS>gq;
AllOne() {
mp.clear();
}
void inc(string key) {
mp[key]++;
lq.push({mp[key],key});
gq.push({mp[key],key});
}
void dec(string key) {
mp[key]--;
if(mp[key]==0)return ;
lq.push({mp[key],key});
gq.push({mp[key],key});
}
string getMaxKey() {
while(gq.size()){
auto [num,s]=gq.top();
if(mp[s]==num)return s;
gq.pop();
}
return "";
}
string getMinKey() {
while(lq.size()){
auto [num,s]=lq.top();
if(mp[s]==num)return s;
lq.pop();
}
return "";
}
};
/**
* Your AllOne object will be instantiated and called as such:
* AllOne* obj = new AllOne();
* obj->inc(key);
* obj->dec(key);
* string param_3 = obj->getMaxKey();
* string param_4 = obj->getMinKey();
*/