Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
Idea
Use HashMap to cache key and value.
Use PriorityQueue to mark LRU item as the hottest. Drop coldest element when over capacity.
A Java Solution
Scaffold
It’s difficult to participate in Clojure’s abstraction for lacking of documentations.
Anyway, a helper function from clojure programming is really useful for us to
dive into it.
By looking at the output of the ancestors and methods of them, we can
determine what to do next:
To implement a LRU Cache, we need to implement those methods.
Some trival knowledge:
cons is the name that backs conj;
equiv is similar to equals, but ensures sane equivalence semantics when applied to numerics
There is two assoc definition, but only 1 is available. The one in clojure.lang.Associative will be replaced by clojure.lang.IPersistentMap. That means we only need to implement the one in clojure.lang.Associative.
Nothing ever uses assocEx anymore. It is a remnant of an earlier time. If you are writing your own map type, you can implement (assocEx [m k v] (throw (Exception.))).1
Solution
Improvements
LRU remove: O(N). A better solution is using PriorityDataStructure to reduce to O(1).
Use Memcached or Redis to replace clojure map and list for better scalable.
Why not rebuild a wheel? https://github.com/clojure/core.cache/wiki/LRU