diff --git a/java/all-oone-data-structure.java b/java/all-oone-data-structure.java new file mode 100644 index 0000000..4c03e66 --- /dev/null +++ b/java/all-oone-data-structure.java @@ -0,0 +1,119 @@ +import java.util.HashMap; + +class AllOne { + private class Node { + int freq; + Node prev, next; + Set keys = new HashSet<>(); + + Node(int freq) { + this.freq = freq; + } + + Node(int freq, Node prev, Node next) { + this.freq = freq; + + this.prev = prev; + prev.next = this; + + this.next = next; + next.prev = this; + } + + void link(Map map, String key) { + keys.add(key); + map.put(key, this); + } + + void remove() { + var prev = this.prev; + var next = this.next; + + prev.next = next; + next.prev = prev; + } + } + + Node head, tail; + Map map = new HashMap<>(); + + public AllOne() { + head = new Node(0); + tail = new Node(0); + + head.next = tail; + tail.prev = head; + } + + public void inc(String key) { + if (!map.containsKey(key)) { + var first = head.next; + if (first != tail && first.freq <= 1) { + first.link(map, key); + return; + } + + var newNode = new Node(1, head, first); + newNode.link(map, key); + return; + } + + var node = map.get(key); + var freq = node.freq; + node.keys.remove(key); + + var next = node.next; + if (next != tail && next.freq == freq + 1) { + next.link(map, key); + } else { + var newNode = new Node(freq + 1, node, next); + newNode.link(map, key); + } + + if (node.keys.isEmpty()) { + node.remove(); + } + } + + public void dec(String key) { + if (!map.containsKey(key)) { + return; + } + + var node = map.get(key); + var freq = node.freq; + node.keys.remove(key); + + if (freq == 1) { + map.remove(key); + } else { + var prev = node.prev; + if (prev != head && prev.freq == freq - 1) { + prev.link(map, key); + } else { + var newNode = new Node(freq - 1, prev, node); + newNode.link(map, key); + } + } + + if (node.keys.isEmpty()) { + node.remove(); + } + } + + 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(); + } +}