【LetMeFly】Caché 146.LRU: lista doblemente enlazada + hash
Enlace de pregunta de Likou: https://leetcode.cn/problems/lru-cache/
LRUCache
:
LRUCache(int capacity)
Inicialice la caché LRU con un número entero positivo como capacidadcapacity
int get(int key)
Si la palabra clavekey
existe en la memoria caché, se devuelve el valor de la palabra clave; de lo contrario, se devuelve-1
.void put(int key, int value)
Si la palabra clavekey
ya existe, cambie su valor de datosvalue
; si no existe, inserte el grupo en la cachékey-value
. Si una operación de inserción hace que se exceda el número de palabras clave ,capacity
se debe desalojar la palabra clave más antigua no utilizada .
Funciona get
y put
debe O(1)
ejecutarse con una complejidad de tiempo promedio de .
Ejemplo:
Entrada ["LRUCache", "poner", "poner", "obtener", "poner", "obtener", "poner", "obtener", "obtener", "obtener"] [[2], [1 , 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] salida [nulo, nulo, nulo , 1 , null, -1, null, -1, 3, 4] Explicación de LRUCache lRUCache = new LRUCache(2); lRUCache.put(1, 1); // El caché es {1=1} lRUCache.put(2 , 2 ); // El caché es {1=1, 2=2} lRUCache.get(1); // Devuelve 1 lRUCache.put(3, 3); // Esta operación invalidará la palabra clave 2 y el caché es {1 =1, 3=3} lRUCache.get(2); // Devuelve -1 (no encontrado) lRUCache.put(4, 4); // Esta operación invalidará la palabra clave 1 y el caché es {4= 4, 3=3} lRUCache.get(1); // Devuelve -1 (no encontrado) lRUCache.get(3); // Devuelve 3 lRUCache.get(4); // Devuelve 4
pista:
1 <= capacity <= 3000
0 <= key <= 10000
0 <= value <= 105
- En la mayoría de los momentos de llamada y
2 * 105
get
put
Método 1: lista doblemente enlazada + hash
Utilice uno 双向链表
como caché LRU. Los nodos más cercanos al encabezado de la lista enlazada se utilizan más recientemente.
Utilice una tabla hash para implementar la función de key
mapeo de a 节点
.
Para asignar desde el nodo al valor clave de la tabla hash , key
también se almacena en el nodo una copia adicional del key
valor del nodo:
class LRU_Node {
public:
LRU_Node* previous, *next;
int key, value;
}
Para facilitar la operación, puede agregar un nodo vacío al principio y al final de la lista doblemente vinculada para evitar el juicio especial de "si está vacío".
Para obtener operación:
Si existe en la tabla hash key
, la tabla hash asigna el nodo, el nodo se mueve al primer nodo de la lista vinculada y se devuelve el nodo value
.
Si no existe en la tabla hash key
, se devolverá directamente -1
.
Para operación de venta:
Si el nodo existe en la tabla hash key
, la tabla hash asigna el nodo, el valor del nodo se actualiza y el nodo se mueve al primer nodo de la lista vinculada.
Si el nodo no existe en la tabla hash key
, cree el nodo y colóquelo como el primer nodo en la lista vinculada. Si la capacidad de la tabla hash es mayor que la capacidad máxima, tail.previous
se obtiene el último nodo, el nodo se elimina de la tabla hash key
y el nodo se elimina de la lista vinculada.
- Complejidad temporal: la complejidad temporal de cada operación es O (1) O (1)o ( 1 )
- Complejidad del espacio O (max (put, capacidad)) O(max(put, capacidad))O ( máx ( poner , _ _ _capacidad ) ) _ _ _ _ _ _
código de CA
C++
class LRU_Node {
public:
LRU_Node* previous, *next;
int key, value;
LRU_Node(LRU_Node* previous, LRU_Node* next, int key, int value) {
this->previous = previous;
this->next = next;
this->key = key;
this->value = value;
}
};
class LRUCache {
private:
LRU_Node* head, *tail;
int capacity;
unordered_map<int, LRU_Node*> ma;
void refresh(int key, int value) {
LRU_Node* thisNode = ma[key];
thisNode->value = value;
LRU_Node* previous = thisNode->previous, *next = thisNode->next;
previous->next = next, next->previous = previous;
thisNode->next = head->next;
head->next = thisNode;
thisNode->previous = head;
thisNode->next->previous = thisNode;
}
public:
LRUCache(int capacity) {
head = new LRU_Node(nullptr, nullptr, 0, 0);
tail = new LRU_Node(head, nullptr, 0, 0);
head->next = tail;
this->capacity = capacity;
}
int get(int key) {
if (ma.count(key)) {
refresh(key, ma[key]->value);
return ma[key]->value;
}
return -1;
}
void put(int key, int value) {
if (ma.count(key)) {
refresh(key, value);
return;
}
LRU_Node* thisNode = new LRU_Node(head, head->next, key, value);
ma[key] = thisNode;
head->next = thisNode, thisNode->next->previous = thisNode;
if (ma.size() > capacity) {
LRU_Node* toRemove = tail->previous;
ma.erase(toRemove->key);
toRemove->previous->next = tail;
tail->previous = toRemove->previous;
}
}
void debug() {
cout << "Now size: " << ma.size() << ": [";
LRU_Node* p = head->next;
while (p != tail) {
if (p != head->next) {
cout << ", ";
}
cout << "(" << p->key << "|" << p->value << ")";
p = p->next;
}
cout << "] | [";
p = tail->previous;
while (p != head) {
if (p != tail->previous) {
cout << ", ";
}
cout << "(" << p->key << "|" << p->value << ")";
p = p->previous;
}
cout << "]" << endl;
}
};
Pitón
class LRU_Node:
def __init__(self, previous, next, key, value):
self.previous = previous
self.next = next
self.key = key
self.value = value
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.head = LRU_Node(None, None, 0, 0)
self.tail = LRU_Node(self.head, None, 0, 0)
self.head.next = self.tail
self.ma = dict()
def move2first(self, thisNode: LRU_Node):
thisNode.previous.next = thisNode.next
thisNode.next.previous = thisNode.previous
thisNode.previous = self.head
thisNode.next = self.head.next
self.head.next = thisNode
thisNode.next.previous = thisNode
def get(self, key: int) -> int:
if key in self.ma:
self.move2first(self.ma[key])
return self.ma[key].value
return -1
def put(self, key: int, value: int) -> None:
if key in self.ma:
thisNode = self.ma[key]
thisNode.value = value
self.move2first(thisNode)
else:
thisNode = LRU_Node(self.head, self.head.next, key, value)
self.ma[key] = thisNode
self.head.next = thisNode
thisNode.next.previous = thisNode
if len(self.ma) > self.capacity:
toRemove = self.tail.previous
del self.ma[toRemove.key]
toRemove.previous.next = self.tail
self.tail.previous = toRemove.previous
El artículo se publica simultáneamente en CSDN. No es fácil ser original. Adjunte el enlace al artículo original después de la reimpresión con el consentimiento del autor ~
Tisfy: https://letmefly.blog.csdn.net/article/details/133241877