Design a data structure to store the strings' count with the ability to return the strings with minimum and maximum counts.
Implement the AllOne
class:
AllOne()
Initializes the object of the data structure.inc(String key)
Increments the count of the string key
by 1
. If key
does not exist in the data structure, insert it with count 1
.dec(String key)
Decrements the count of the string key
by 1
. If the count of key
is 0
after the decrement, remove it from the data structure. It is guaranteed that key
exists in the data structure before the decrement.getMaxKey()
Returns one of the keys with the maximal count. If no element exists, return an empty string ""
.getMinKey()
Returns one of the keys with the minimum count. If no element exists, return an empty string ""
.Note that each function must run in O(1)
average time complexity.
Example 1:
Input ["AllOne", "inc", "inc", "getMaxKey", "getMinKey", "inc", "getMaxKey", "getMinKey"] [[], ["hello"], ["hello"], [], [], ["leet"], [], []] Output [null, null, null, "hello", "hello", null, "hello", "leet"] Explanation AllOne allOne = new AllOne(); allOne.inc("hello"); allOne.inc("hello"); allOne.getMaxKey(); // return "hello" allOne.getMinKey(); // return "hello" allOne.inc("leet"); allOne.getMaxKey(); // return "hello" allOne.getMinKey(); // return "leet"
Constraints:
1 <= key.length <= 10
key
consists of lowercase English letters.dec
, key
is existing in the data structure.5 * 10^4
calls will be made to inc
, dec
, getMaxKey
, and getMinKey
.【C++】
- class AllOne {
- unordered_map
int> m;// store string -> val - map<int,unordered_set
> mp;// val -> set of strings with value as val - public:
- AllOne() {}
-
- void inc(string key) {
- if (m.find(key) == m.end()) {
- m[key]=1;
- mp[1].insert(key);
- } else {
- int p=m[key];
- m[key]=p+1;
- mp[p].erase(key);
- if (mp[p].size() == 0) {mp.erase(p);}
- mp[p+1].insert(key);
- }
- }
-
- void dec(string key) {
- int p=m[key];
- if (p==1) {
- m.erase(key);
- mp[p].erase(key);
- if(mp[p].size()==0) {mp.erase(p);}
- } else {
- m[key]=p-1;
- mp[p].erase(key);
- if (mp[p].size() == 0) {mp.erase(p);}
- mp[p-1].insert(key);
- }
- }
-
- string getMaxKey() {
- string s="";
- if(mp.size()) {
- auto p=mp.rbegin()->second.begin();
- s=*p;
- }
- return s;
- }
-
- string getMinKey() {
- string s="";
- if (mp.size()) {
- auto p=mp.begin()->second.begin();
- s=*p;
- }
- return s;
- }
- };
-
- /**
- * 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();
- */
【Java】
- class AllOne {
- static class Bucket {
- int count;
- Set
keys; - Bucket prev;
- Bucket next;
- public Bucket(int count) {
- this.count = count;
- keys = new LinkedHashSet<>();
- }
-
- public void insertAfter(Bucket newBucket) {
- Bucket nextBucket = this.next;
- this.next = newBucket;
- nextBucket.prev = newBucket;
- newBucket.prev = this;
- newBucket.next = nextBucket;
- }
- }
-
- private final Map
keysToBucket; - private final Bucket head;
- private final Bucket tail;
-
- public AllOne() {
- keysToBucket = new HashMap<>();
- head = new Bucket(0);
- tail = new Bucket(0);
- head.next = tail;
- tail.prev = head;
- }
-
- public void inc(String key) {
- Bucket currBucket = keysToBucket.getOrDefault(key, head);
- Bucket nextBucket = currBucket.next;
- if (nextBucket.count != currBucket.count + 1) {
- nextBucket = new Bucket(currBucket.count + 1);
- currBucket.insertAfter(nextBucket);
- }
- nextBucket.keys.add(key);
- removeKeyFromBucket(currBucket, key);
- keysToBucket.put(key, nextBucket);
- }
-
- public void dec(String key) {
- Bucket currBucket = keysToBucket.get(key), prevBucket = currBucket.prev;
- if (prevBucket.count != currBucket.count - 1) {
- prevBucket = new Bucket(currBucket.count - 1);
- currBucket.prev.insertAfter(prevBucket);
- }
- if (currBucket.count != 1) {prevBucket.keys.add(key);}
- removeKeyFromBucket(currBucket, key);
- keysToBucket.put(key, prevBucket);
- }
-
- public String getMaxKey() {
- if (tail.prev == head) {return "";}
- return tail.prev.keys.iterator().next();
- }
-
- public String getMinKey() {
- if (head.next == tail) {return "";}
- return head.next.keys.iterator().next();
- }
-
- private void deleteBucket(Bucket bucket) {
- Bucket prev = bucket.prev, next = bucket.next;
- prev.next = next;
- next.prev = prev;
- bucket.next = null;
- bucket.prev = null;
- }
-
- private void removeKeyFromBucket(Bucket bucket, String key) {
- if (bucket.count > 0) {
- bucket.keys.remove(key);
- if (bucket.keys.isEmpty()) {deleteBucket(bucket);}
- }
- }
- }
-
- /**
- * 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();
- */