题目描述
解法一:哈希表+AVL(C++)
这里的AVL树主要采用C++ STL: :set
时间复杂度: get 时间复杂度 O ( log n ) O(\log n) O(logn),put 时间复杂度 O ( log n ) O(\log n) O(logn),操作的时间复杂度瓶颈在于平衡二叉树的插入删除均需要 O ( log n ) O(\log n) O(logn) 的时间。
参考 官方题解
struct Node{
int cnt; // 频度
int time; // 最近使用时间
int key, value;
Node(int _cnt, int _time, int _key, int _value): cnt(_cnt), time(_time), key(_key), value(_value){}
bool operator < (const Node& rhs) const {
return cnt == rhs.cnt?(time<rhs.time):(cnt<rhs.cnt);
}
};
class LFUCache {
int capacity, time;
unordered_map<int, Node> key_table;
set<Node> S;
public:
LFUCache(int _capacity) {
capacity = _capacity;
time = 0;
key_table.clear();
S.clear();
}
int get(int key) {
if(!capacity) return -1;
auto it = key_table.find(key);
if(it==key_table.end()) return -1;
Node cache = it->second;
S.erase(cache);
cache.cnt += 1;
cache.time = ++time;
S.insert(cache);
it->second = cache;
return cache.value;
}
void put(int key, int value) {
if(!capacity) return;
auto it = key_table.find(key);
if(it==key_table.end())
{
if(key_table.size()==capacity)
{
key_table.erase(S.begin()->key);
S.erase(S.begin());
}
Node cache = Node(1, ++time, key, value);
key_table.insert(make_pair(key, cache));
S.insert(cache);
}
else
{
Node cache = it->second;
S.erase(cache);
cache.cnt += 1;
cache.time = ++time;
cache.value = value;
S.insert(cache);
it->second = cache;
}
}
};
/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache* obj = new LFUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
解法二:双向链表(Python)
准备两个字典,
- key与freq映射,为了找key在哪个频率下;
- key与value映射,为了找key对应的value值,这个需要一个有序字典OrderedDict,为了好弹出同一个频率下,最开始加入的key(当然是容量不够,需要弹出的时候)
对于第二个字典,可以使用python自带库,也可以使用双向链表实现
class Node:
def __init__(self, key, val):
self.key = key
self.val = val
self.freq = 1
self.prev = self.next = None
class DCLinkedList:
def __init__(self):
self.dummy = Node(None, None)
self.dummy.next = self.dummy
self.dummy.prev = self.dummy
self.size = 0
def append(self, node):
# 尾插入
node.prev = self.dummy.prev
node.next = self.dummy
node.prev.next = node
self.dummy.prev = node
self.size += 1
def pop(self, node=None):
# 头删除
if self.size == 0: return
if node is None:
node = self.dummy.next
node.prev.next = node.next
node.next.prev = node.prev
self.size -= 1
return node
class LFUCache:
def __init__(self, capacity: int):
from collections import defaultdict
self.key_to_node = {}
self.freq = defaultdict(DCLinkedList)
self.min_freq = 0
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self.key_to_node: return -1
node = self.key_to_node[key]
node_freq = node.freq
self.freq[node_freq].pop(node)
if self.min_freq == node_freq and self.freq[node_freq].size == 0:
self.min_freq += 1
node.freq += 1
self.freq[node.freq].append(node)
return node.val
def put(self, key: int, value: int) -> None:
if not self.capacity: return
if key in self.key_to_node:
node = self.key_to_node[key]
node_freq = node.freq
self.freq[node_freq].pop(node)
if self.min_freq == node_freq and self.freq[node_freq].size == 0:
self.min_freq += 1
node.freq += 1
node.val = value
self.freq[node.freq].append(node)
else:
if len(self.key_to_node) == self.capacity:
node = self.freq[self.min_freq].pop()
self.key_to_node.pop(node.key)
node = Node(key, value)
self.key_to_node[key] = node
self.freq[1].append(node)
self.min_freq = 1
# Your LFUCache object will be instantiated and called as such:
# obj = LFUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)