|
@@ -0,0 +1,106 @@
|
|
|
+type biNode struct {
|
|
|
+ key int
|
|
|
+ val int
|
|
|
+ cnt int
|
|
|
+ prev *biNode
|
|
|
+ next *biNode
|
|
|
+}
|
|
|
+
|
|
|
+type biList struct {
|
|
|
+ head *biNode
|
|
|
+ tail *biNode
|
|
|
+}
|
|
|
+
|
|
|
+func newBiList() *biList {
|
|
|
+ head, tail := &biNode{}, &biNode{}
|
|
|
+ head.next = tail
|
|
|
+ tail.prev = head
|
|
|
+ li := &biList{head, tail}
|
|
|
+ return li
|
|
|
+}
|
|
|
+
|
|
|
+func (li *biList) remove(node *biNode) {
|
|
|
+ node.prev.next = node.next
|
|
|
+ node.next.prev = node.prev
|
|
|
+}
|
|
|
+
|
|
|
+type LFUCache struct {
|
|
|
+ capacity int
|
|
|
+ size int
|
|
|
+ min int
|
|
|
+ cache map[int]*biNode
|
|
|
+ freq map[int]*biList
|
|
|
+}
|
|
|
+
|
|
|
+func Constructor(capacity int) LFUCache {
|
|
|
+ var lfu LFUCache
|
|
|
+ lfu.capacity = capacity
|
|
|
+ lfu.cache = make(map[int]*biNode)
|
|
|
+ lfu.freq = make(map[int]*biList)
|
|
|
+ return lfu
|
|
|
+}
|
|
|
+
|
|
|
+func (this *LFUCache) Get(key int) int {
|
|
|
+ if node, ok := this.cache[key]; ok {
|
|
|
+ this.touch(node)
|
|
|
+ return node.val
|
|
|
+ }
|
|
|
+ return -1
|
|
|
+}
|
|
|
+
|
|
|
+func (this *LFUCache) Put(key int, value int) {
|
|
|
+ if this.capacity == 0 {
|
|
|
+ return
|
|
|
+ } // Can not put new node.
|
|
|
+ if node, ok := this.cache[key]; ok {
|
|
|
+ this.touch(node)
|
|
|
+ node.val = value
|
|
|
+ return
|
|
|
+ } // If the key already exists, touch it and update the value.
|
|
|
+ if this.size == this.capacity {
|
|
|
+ li := this.freq[this.min]
|
|
|
+ delete(this.cache, li.tail.prev.key)
|
|
|
+ li.remove(li.tail.prev)
|
|
|
+ if li.head.next == li.tail {
|
|
|
+ delete(this.freq, this.min)
|
|
|
+ }
|
|
|
+ this.size--
|
|
|
+ } // If the cache is full, remove the last element in the least freq list.
|
|
|
+ newNode := &biNode{key, value, 1, nil, nil}
|
|
|
+ this.insert(newNode)
|
|
|
+ this.cache[key] = newNode
|
|
|
+ this.min = 1
|
|
|
+ this.size++ // Then, insert new node.
|
|
|
+}
|
|
|
+
|
|
|
+func (this *LFUCache) insert(node *biNode) {
|
|
|
+ li := this.freq[node.cnt]
|
|
|
+ if li == nil {
|
|
|
+ li = newBiList()
|
|
|
+ this.freq[node.cnt] = li
|
|
|
+ }
|
|
|
+ node.next = li.head.next
|
|
|
+ node.prev = li.head
|
|
|
+ li.head.next = node
|
|
|
+ node.next.prev = node
|
|
|
+}
|
|
|
+
|
|
|
+func (this *LFUCache) touch(node *biNode) {
|
|
|
+ li := this.freq[node.cnt]
|
|
|
+ li.remove(node)
|
|
|
+ if li.head.next == li.tail {
|
|
|
+ delete(this.freq, node.cnt)
|
|
|
+ if node.cnt == this.min {
|
|
|
+ this.min++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ node.cnt++
|
|
|
+ this.insert(node)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Your LFUCache object will be instantiated and called as such:
|
|
|
+ * obj := Constructor(capacity);
|
|
|
+ * param_1 := obj.Get(key);
|
|
|
+ * obj.Put(key,value);
|
|
|
+ */
|