LeetCode a daily problem 460. LFU cache hash table to achieve a balanced binary tree + detailed explanations C ++ description

LeetCode a daily problem 460. LFU cache

2020.04.05
Difficulty

topic

Design and implement the least frequently used (LFU) cache data structure. It should support the following operations: get and put.

get (key) - if the key exists in the cache, then get the value (always positive) key, otherwise -1.
put (key, value) - if the key does not exist, or insert set value. When the cache reaches its capacity, it should be in before inserting a new project, the project is not the most frequently used is invalid. In this problem, when there is a tie (i.e., two or more keys having the same frequency), the least recently used key is removed.

Advanced:
you can do two things within (1) the time complexity of O?

Example:

LFUCache cache = new LFUCache (2 / * capacity ( buffer capacity) * /);
cache.put (. 1,. 1);
cache.put (2, 2);
cache.get (. 1); // returns. 1
cache.put (3, 3); // removing 2 Key
cache.get (2); // returns -1 (key not found 2)
cache.get (3); // returns 3
cache.put (. 4,. 4); / / removal. 1 Key
cache.get (. 1); // returns -1 (not found. 1 Key)
cache.get (. 3); // returns. 3
cache.get (4); // returns 4

Solving a problem: balanced binary hash table +

  This problem we can use a combination of balanced binary tree and hash table to solve this problem. STL in our balanced binary tree in C ++ <set>instead <set>of the underlying implementation is a balanced binary tree. The reason unordered_map hash table, then we use here, used here instead of unordered_map map is, unordered_map in the internal implementation of the hash table, query speed is very fast, but the construction of the table at a slower pace, more suitable for the query data.
  Below us, the specific implementation, there are LFUCache () constructor, get () method, put () method first we need to achieve here. Here we need a first data storage structure our each node (the frequency of use, time of use of the cache, the key key, value value), where we use a Node structure. In the structure we write a function assignment Node(int _cnt, int _time, int _key, int _value), assignment help us, since we need to Node then stored into <set>the so we need to override <operator, where <operation rules using symbols 最近最少使用原则calculates, in more detail in the code the interpretation of the rules.
  We need LFUCache class represented variable capacity buffer capacity, time representing the current time, unordered_map<int, Node> hash_map;hash_map for storing key and Node, set<Node> S;a storage node, and automatically ordered from small to large, this is what we need four variables in the class. In the constructor LFUCache(int _capacity), we only need to perform the initialization operations.
  get(int key)Implementation, we only need to be in hash_map find, if found, the return value, and updates the data, did not find -1 is returned
  put(int key, int value)realization method is to key look in hash_map, if found, and then update data (and get () similar), if not to be found, you will need to determine whether full capacity, if full, then delete the least recently used nodes即S的开始结点And then insertion operation, if the capacity is not full, the direct insertion.
Paste the following detailed notes of problem-solving code for your reference:

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);
 */

Implementation of the results:
Here Insert Picture Description

Published 170 original articles · won praise 884 · views 80000 +

Guess you like

Origin blog.csdn.net/qq_43422111/article/details/105322050