Implement a data structure supporting the following operations:
- Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a non-empty string.
- Dec(Key) - If Key's value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If the key does not exist, this function does nothing. Key is guaranteed to be a non-empty string.
- GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string
""
. - GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string
""
.
Challenge: Perform all these in O(1) time complexity.
思路:这题跟 LRU 和 LFU 很类似;都是hashmap,加double linkedlist,这里不同的是,node里面存频率, Integer, 和 Set<String> keys。inc,如果后面的node频率刚好是value +1 ,那么直接把key加到后面的node,如果node.value > curnode.value + 1,那么生成一个新的node。同理 dec, 如果前面的node.value == curnode.value - 1,那么curnode keys remove key, add key into 前面的node,同时跟新hashmap。注意如果curnode.key.size() == 0, 要remove自己,在整个list中间;
class AllOne {
private class Node {
public int value;
public HashSet<String> keys;
public Node pre;
public Node next;
public Node(int value) {
this.value = value;
this.keys = new HashSet<String>();
}
public void removeSelf() {
this.pre.next = this.next;
this.next.pre = this.pre;
}
public void insert(Node pre, Node next) {
this.pre = pre;
pre.next = this;
this.next = next;
next.pre = this;
}
}
private Map<String, Node> hashmap;
private Node head;
private Node tail;
/** Initialize your data structure here. */
public AllOne() {
this.hashmap = new HashMap<String, Node>();
this.head = new Node(0);
this.tail = new Node(Integer.MAX_VALUE);
head.next = tail;
tail.pre = head;
}
/** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */
public void inc(String key) {
if(hashmap.containsKey(key)) {
Node curnode = hashmap.get(key);
Node nextnode = curnode.next;
curnode.keys.remove(key);
hashmap.remove(key);
if(nextnode.value > curnode.value + 1) {
Node newnode = new Node(curnode.value + 1);
newnode.insert(curnode, nextnode);
nextnode = newnode;
}
nextnode.keys.add(key);
hashmap.put(key, nextnode);
if(curnode.keys.size() == 0) {
curnode.removeSelf();
}
} else {
// hashmap don't contains key;
if(head.next.value == 1) {
head.next.keys.add(key);
hashmap.put(key, head.next);
} else {
Node newnode = new Node(1);
newnode.insert(head, head.next);
newnode.keys.add(key);
hashmap.put(key, newnode);
}
}
}
/** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
public void dec(String key) {
if(!hashmap.containsKey(key)) {
return;
}
Node curnode = hashmap.get(key);
Node prenode = curnode.pre;
curnode.keys.remove(key);
hashmap.remove(key);
if(curnode.value > 1) {
if (prenode.value < curnode.value - 1) {
Node newnode = new Node(curnode.value - 1);
newnode.insert(prenode, curnode);
prenode = newnode;
}
prenode.keys.add(key);
hashmap.put(key, prenode);
}
if(curnode.keys.size() == 0) {
curnode.removeSelf();
}
}
/** Returns one of the keys with maximal value. */
public String getMaxKey() {
return tail.pre == head ? "" : tail.pre.keys.iterator().next();
}
/** Returns one of the keys with Minimal value. */
public String getMinKey() {
return head.next == tail ? "" : head.next.keys.iterator().next();
}
}
/**
* 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();
*/