https://leetcode.com/problems/all-oone-data-structure/
用bucket保存同一value的key,bucket是一个双向指针。bucket里面有keySet,有value。保存全局变量keyMap和bucketMap以便于在O(1)时间内找到bucket。
public class AllOne {
Bucket head;
Bucket tail;
HashMap<String, Integer> keyMap;
HashMap<Integer, Bucket> bucketMap;
private class Bucket {
int count;
Set<String> keySet;
Bucket pre;
Bucket next;
public Bucket(int count) {
this.count = count;
keySet = new HashSet<>();
}
}
/** Initialize your data structure here. */
public AllOne() {
head = new Bucket(Integer.MIN_VALUE);
tail = new Bucket(Integer.MIN_VALUE);
head.next = tail;
tail.pre = head;
keyMap = new HashMap<>();
bucketMap = new HashMap<>();
}
/** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */
public void inc(String key) {
if (keyMap.containsKey(key)) {
changeVal(key, 1);
} else {
keyMap.put(key, 1);
if (head.next.count != 1) {
insertAfter(head, new Bucket(1));
}
head.next.keySet.add(key);
bucketMap.put(1, head.next);
}
}
/** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
public void dec(String key) {
if (keyMap.containsKey(key)) {
int count = keyMap.get(key);
if (count == 1) {
keyMap.remove(key);
removeKeyFromBucket(bucketMap.get(count), key);
} else {
changeVal(key, -1);
}
}
}
/** Returns one of the keys with maximal value. */
public String getMaxKey() {
return tail.pre == head ? "" : (String) tail.pre.keySet.iterator().next();
}
/** Returns one of the keys with Minimal value. */
public String getMinKey() {
return head.next == tail ? "" : (String) head.next.keySet.iterator().next();
}
private void changeVal(String key, int offset) {
int count = keyMap.get(key);
keyMap.put(key, count + offset);
Bucket curBucket = bucketMap.get(count);
Bucket newBucket;
if (bucketMap.containsKey(count + offset)) {
newBucket = bucketMap.get(count + offset);
} else {
newBucket = new Bucket(count + offset);
bucketMap.put(count + offset, newBucket);
insertAfter(offset == 1 ? curBucket : curBucket.pre, newBucket);
}
newBucket.keySet.add(key);
removeKeyFromBucket(curBucket, key);
}
private void insertAfter(Bucket pre, Bucket after) {
after.next = pre.next;
after.pre = pre;
pre.next.pre = after;
pre.next = after;
}
private void removeKeyFromBucket(Bucket bucket, String key) {
bucket.keySet.remove(key);
if (bucket.keySet.size() == 0) {
removeFromBucketList(bucket);
bucketMap.remove(bucket.count);
}
}
private void removeFromBucketList(Bucket bucket) {
bucket.pre.next = bucket.next;
bucket.next.pre = bucket.pre;
bucket.next = null;
bucket.pre = null;
}
}
/**
* 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();
*/