请你设计一个用于存储字符串计数的数据结构,并能够返回计数最小和最大的字符串。
实现 AllOne 类:
AllOne() 初始化数据结构的对象。
inc(String key) 字符串 key 的计数增加 1 。如果数据结构中尚不存在 key ,那么插入计数为 1 的 key 。
dec(String key) 字符串 key 的计数减少 1 。如果 key 的计数在减少后为 0 ,那么需要将这个 key 从数据结构中删除。测试用例保证:在减少计数前,key 存在于数据结构中。
getMaxKey() 返回任意一个计数最大的字符串。如果没有元素存在,返回一个空字符串 “” 。
getMinKey() 返回任意一个计数最小的字符串。如果没有元素存在,返回一个空字符串 “” 。
示例:
输入
[“AllOne”, “inc”, “inc”, “getMaxKey”, “getMinKey”, “inc”, “getMaxKey”, “getMinKey”]
[[], [“hello”], [“hello”], [], [], [“leet”], [], []]
输出
[null, null, null, “hello”, “hello”, null, “hello”, “leet”]
解释
AllOne allOne = new AllOne();
allOne.inc(“hello”);
allOne.inc(“hello”);
allOne.getMaxKey(); // 返回 “hello”
allOne.getMinKey(); // 返回 “hello”
allOne.inc(“leet”);
allOne.getMaxKey(); // 返回 “hello”
allOne.getMinKey(); // 返回 “leet”
提示:
1 <= key.length <= 10
key 由小写英文字母组成
测试用例保证:在每次调用 dec 时,数据结构中总存在 key
最多调用 inc、dec、getMaxKey 和 getMinKey 方法 5 * 104 次
class AllOne {
//采用双向链表+hash表
//unordered_set 存储key集合,int表示集合中每个key出现的次数,同一个集合中出现次数是相同的
list<pair<unordered_set<string>, int>> l;
//保存每个key对应的链表的迭代器位置
unordered_map<string, list<pair<unordered_set<string>, int>>::iterator>key2index;
public:
AllOne() {
}
void inc(string key) {
//如果key存在
if (key2index.count(key)) {
//如果是最后一个或者下一个的cur->count < next->count - 1 创建并插入新节点
auto cur = key2index[key];
auto nxt = next(cur);
if (nxt == l.end() || cur->second < nxt->second - 1) {
unordered_set<string>s({key});
key2index[key] = l.emplace(nxt, s, cur->second + 1);
} else {
nxt->first.emplace(key);
key2index[key] = nxt;
}
//删除cur中key,如果cur无元素,则删除cur
cur->first.erase(key);
if (cur->first.size() == 0) {
l.erase(cur);
}
} else { //如果是空的 插入一个节点,如果第一个节点 > 1
if (l.size() == 0 || l.begin()->second > 1) {
unordered_set<string>s({key});
l.emplace(l.begin(), s, 1);
} else {
l.begin()->first.emplace(key);
}
key2index[key] = l.begin();
}
}
void dec(string key) {
auto cur = key2index[key];
//如果基数>1,且 cur = begin() || cur->last->second < cur->second - 1,插入新的节点
if (cur->second > 1 ) {
if (cur == l.begin() || prev(cur)->second < cur->second - 1) {
unordered_set<string>s({key});
key2index[key] = l.emplace(cur, s, cur->second - 1);
} else {
prev(cur)->first.emplace(key);
key2index[key] = prev(cur);
}
} else {
key2index.erase(key);
}
cur->first.erase(key);
if (cur->first.empty()) {
l.erase(cur);
}
}
string getMaxKey() {
return l.size() > 0? *(l.rbegin()->first.begin()) : "";
}
string getMinKey() {
return l.size() > 0? *(l.begin()->first.begin()) : "";
}
};
/**
* 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();
*/