# 460-lfu-cache Try it on leetcode ## Description

Design and implement a data structure for a Least Frequently Used (LFU) cache.

Implement the LFUCache class:

To determine the least frequently used key, a use counter is maintained for each key in the cache. The key with the smallest use counter is the least frequently used key.

When a key is first inserted into the cache, its use counter is set to 1 (due to the put operation). The use counter for a key in the cache is incremented either a get or put operation is called on it.

The functions get and put must each run in O(1) average time complexity.

 

Example 1:

Input
["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, 3, null, -1, 3, 4]

Explanation
// cnt(x) = the use counter for key x
// cache=[] will show the last used order for tiebreakers (leftmost element is  most recent)
LFUCache lfu = new LFUCache(2);
lfu.put(1, 1);   // cache=[1,_], cnt(1)=1
lfu.put(2, 2);   // cache=[2,1], cnt(2)=1, cnt(1)=1
lfu.get(1);      // return 1
                 // cache=[1,2], cnt(2)=1, cnt(1)=2
lfu.put(3, 3);   // 2 is the LFU key because cnt(2)=1 is the smallest, invalidate 2.
                 // cache=[3,1], cnt(3)=1, cnt(1)=2
lfu.get(2);      // return -1 (not found)
lfu.get(3);      // return 3
                 // cache=[3,1], cnt(3)=2, cnt(1)=2
lfu.put(4, 4);   // Both 1 and 3 have the same cnt, but 1 is LRU, invalidate 1.
                 // cache=[4,3], cnt(4)=1, cnt(3)=2
lfu.get(1);      // return -1 (not found)
lfu.get(3);      // return 3
                 // cache=[3,4], cnt(4)=1, cnt(3)=3
lfu.get(4);      // return 4
                 // cache=[4,3], cnt(4)=2, cnt(3)=3

 

Constraints:

 

 
## Solution(Python) ```Python class ListNode: def __init__(self, key, val): self.key = key self.val = val self.freq = 1 self.prev = None self.next = None class DLL: def __init__(self): self.head = ListNode(0, 0) self.tail = ListNode(0, 0) self.head.next = self.tail self.tail.prev = self.head self.size = 0 def insertHead(self, node): headNext = self.head.next headNext.prev = node self.head.next = node node.prev = self.head node.next = headNext self.size += 1 def removeNode(self, node): node.next.prev = node.prev node.prev.next = node.next self.size -= 1 def removeTail(self): tail = self.tail.prev self.removeNode(tail) return tail class LFUCache: def __init__(self, capacity: int): self.cache = {} self.freqTable = collections.defaultdict(DLL) self.capacity = capacity self.minFreq = 0 def get(self, key: int) -> int: if key not in self.cache: return -1 return self.updateCache(self.cache[key], key, self.cache[key].val) def put(self, key: int, value: int) -> None: if not self.capacity: return if key in self.cache: self.updateCache(self.cache[key], key, value) else: if len(self.cache) == self.capacity: prevTail = self.freqTable[self.minFreq].removeTail() del self.cache[prevTail.key] node = ListNode(key, value) self.freqTable[1].insertHead(node) self.cache[key] = node self.minFreq = 1 def updateCache(self, node, key, value): node = self.cache[key] node.val = value prevFreq = node.freq node.freq += 1 self.freqTable[prevFreq].removeNode(node) self.freqTable[node.freq].insertHead(node) if prevFreq == self.minFreq and self.freqTable[prevFreq].size == 0: self.minFreq += 1 return node.val ```