LeetCode un problema 460. tabla de caché LFU hash de todos los días para lograr un árbol binario balanceado + explicaciones de descripción detallada de C ++

LeetCode un problema de caché 460. diaria LFU

04/05/2020
dificultad

título

Diseñar e implementar la estructura de datos (LFU) caché utilizada con menos frecuencia. Debe apoyar las siguientes operaciones: obtener y poner.

get (clave) - Si existe la clave en la memoria caché, a continuación, obtener el valor de la clave (siempre positivo), en otro caso -1.
poner (clave, valor) - si la clave no existe, o inserto valor establecido. Cuando la caché alcanza su capacidad, debe estar en antes de insertar un nuevo proyecto, el proyecto no es el más frecuentemente utilizado es válido. En este problema, cuando hay un empate (es decir, dos o más teclas que tienen la misma frecuencia), se retira la llave menos utilizado recientemente.

Avanzado:
puede hacer dos cosas dentro de (1) el tiempo de complejidad de O?

Ejemplo:

LFUCache cache = new LFUCache (2 / * capacidad ( capacidad tampón) * /);
cache.put (1 ,. 1.);
Cache.put (2, 2);
cache.get (1.); // devuelve 1.
Cache.put (3, 3); // eliminación de 2 Key
cache.get (2); // devuelve -1 (clave no encontró 2)
cache.get (3); // devuelve 3
(. 4 ,. 4) cache.put; / . / extracción 1 Key
cache.get (1.); // devuelve -1 (no encontrado 1 Key.)
cache.get (3.); // devuelve 3.
cache.get (4); // devuelve 4

La solución de un problema: equilibrado de hash binario de mesa +

  Este problema se puede utilizar una combinación de árbol binario equilibrado y tabla hash para resolver este problema. STL en nuestro árbol binario equilibrado en C ++ <set>en lugar <set>de la implementación subyacente es un árbol binario equilibrado. La tabla hash unordered_map razón, entonces se utiliza aquí, se usa aquí en lugar de un mapa unordered_map es, unordered_map en la implementación interna de la tabla hash, la velocidad de consulta es muy rápido, pero la construcción de la tabla a un ritmo más lento, más adecuado para los datos de la consulta.
  Debajo de nosotros, la implementación específica, hay LFUCache () constructor, método get (), método put () primero tenemos que lograr aquí. Aquí tenemos una primera estructura de almacenamiento de datos a nuestro cada nodo (la frecuencia de uso, el tiempo de uso de la memoria caché, la tecla clave, valor valor), donde se utiliza una estructura de nodos. En la estructura escribimos una asignación de funciones Node(int _cnt, int _time, int _key, int _value), ayuda asignación de nosotros, ya que tenemos que Nodo luego se almacena en <set>el por lo que necesitamos para anular <operador, donde <las reglas de operación utilizando símbolos 最近最少使用原则calcula, con más detalle en el código la interpretación de las reglas.
  Necesitamos clase LFUCache representado capacidad de amortiguación de capacidad variable, el tiempo que representa la hora actual, unordered_map<int, Node> hash_map;hash_map para el almacenamiento de claves y nodo, set<Node> S;un nodo de almacenamiento, y ordenó de forma automática desde pequeñas a grandes, esto es lo que necesitamos cuatro variables en la clase. En el constructor LFUCache(int _capacity), sólo tenemos que ejecutar la inicialización.
  get(int key)Aplicación, sólo necesita estar en hash_map hallazgo, si lo encuentra, el valor de retorno, y actualiza los datos, no encuentra -1 se devuelve
  put(int key, int value)método de realización es de aspecto clave en hash_map, si lo encuentra, y luego actualizar datos (y get () similar), si no se encuentra, tendrá que determinar si la capacidad total, si está lleno, a continuación, elimine los nodos menos recientemente utilizado即S的开始结点Y la operación de inserción a continuación, si la capacidad no está lleno, la inserción directa.
Pegar las siguientes notas detalladas de código de resolución de problemas para su referencia:

struct Node {
    // cnt 表示缓存使用的频率,time 表示缓存的使用时间,key 表示缓存键, value 表示缓存的值
    int cnt, time, key, value;

    // 赋值函数
    Node(int _cnt, int _time, int _key, int _value){
        cnt = _cnt;
        time = _time;
        key = _key;
        value = _value;
    }
    // 重载运算符,因为这里使用set,需要对`<`运算符进行重载
    bool operator < (const Node& mid) const {
        // 返回的值为:如果比较的Node和当前的Node的使用频率一样,则返回比较两者的使用时间,如果当前时间小则返回1(当前的最近使用,最近最少使用原则),否则返回0;如果使用频率不一样,则返回两者时间的比值,即以cnt的大小作为判断。
        return cnt == mid.cnt ? time < mid.time : cnt < mid.cnt;
    }
};
class LFUCache {
    // capacity 表示缓存容量,time 表示当前时间
    int capacity, time;
    // 这里使用了unordered_map而不是map,因为unordered_map内部实现了哈希表,查找速度快,适用于查找多的结构
    // hash_map用于存储key和Node
    unordered_map<int, Node> hash_map;
    // S用于存储Node,并且自动的排序,从小到大
    set<Node> S;
public:
    LFUCache(int _capacity) {
        // 第一次调用时,进行初始化
        capacity = _capacity;
        time = 0;
        hash_map.clear();
        S.clear();
    }
    
    int get(int key) {
        // 如果容量为空,则一直无法存储,直接返回-1
        if (capacity == 0) 
            return -1;
        // 在hash_map中查找key
        auto it = hash_map.find(key);
        // 如果哈希表中没有键 key,返回 -1
        if (it == hash_map.end()) 
            return -1;
        // 如果查找到了key,则从哈希表中得到旧的缓存,这里的second即为unordered_map<int, Node> hash_map;中的第二个参数,Node类型,
        Node cache = it -> second;
        // 从平衡二叉树中删除旧的缓存
        S.erase(cache);
        // 将旧缓存更新,使用频次+1,时间为当前时间+1
        cache.cnt += 1;
        cache.time = ++time;
        // 将新缓存重新放入哈希表和平衡二叉树中
        S.insert(cache);
        it -> second = cache;
        return cache.value;
    }
    
    void put(int key, int value) {
        // 如果容量为0,则直接返回,即不操作
        if (capacity == 0) 
            return;
        // 在hash_map中查找Key
        auto it = hash_map.find(key);
        // 如果没查找到key,则进行插入
        if (it == hash_map.end()) {
            // 如果到达缓存容量上限
            if (hash_map.size() == capacity) {
                // 分别从哈希表和平衡二叉树中删除最近最少使用的缓存,S是按照最近最少使用进行排序的,所以第一个也就是最近最少使用的那个。
                hash_map.erase(S.begin() -> key);
                S.erase(S.begin());
            }
            // 创建新的缓存,使用频次初始为1,时间为当前时间+1,key,value即参数中的键值对
            Node cache = Node(1, ++time, key, value);
            // 将新缓存放入哈希表和平衡二叉树中
            hash_map.insert(make_pair(key, cache));
            S.insert(cache);
        }
        else {
            // 如果找到了key,则进行一个更新操作,和get()的更新操作类似
            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);
 */

Aplicación de los resultados:
Aquí Insertar imagen Descripción

Publicados 170 artículos originales · ganado elogios 884 · Vistas a 80000 +

Supongo que te gusta

Origin blog.csdn.net/qq_43422111/article/details/105322050
Recomendado
Clasificación