LRU & LFU Cache (Leetcode 146, Leetcode 460)

先来看LRU Cache,LRU Cache的重点就是建立一个 map::iterator> 的hash table。key存需要找的key,value是list的iterator。

而这个list> 存的就是key value pair。在get或set时,要把这个 pair 从当前位置,放到栈顶。这个是用list.splice函数实现的。splice函数的用法如下:

list.splice(position, list name, list iterator)
lst.splice(lst.begin(), lst, it);

注意:在这里统一一下,无论LRU还是LFU Cache, 一律先删,再加。

class LRUCache {
public:
    LRUCache(int capacity) {
        this->capacity = capacity;
    }
    
    int get(int key) {
        if(!mp.count(key)) return -1;
        auto it = mp[key];
        lst.splice(lst.begin(), lst, it);
        mp[key] = lst.begin();
        return it->second;
    }
    
    void put(int key, int value) {
        if(get(key) != -1){
            mp[key]->second = value;
        }
        else{
            if(lst.size() == capacity){
                auto it = lst.back();
                lst.pop_back();
                mp.erase(it.first);
            }
            lst.push_front({key, value});
            mp[key] = lst.begin();

        }
    }
private:
    int capacity;
    list> lst;
    unordered_map>::iterator> mp;
};

LFU Cache则要复杂不少,具体参考grandyang的LFU solution:
http://www.cnblogs.com/grandyang/p/6258459.html

LFU Cache的经典solution是用doubly linkded list (http://dhruvbird.com/lfu.pdf),上文解法用三个Hashmap模拟了这个doubly linked list,非常巧妙. 另外trick是在set时调用get,并讨论考虑get != -1的情况. 本文变化是当capacity reach full时,将队尾pop出去. 注意,第一个keyValue Hashmap: key => {value, frequency}

纯O(1)的solution:

class LFUCache {
public:
    LFUCache(int capacity) {
        cap = capacity;
    }
    
    int get(int key) {
        if(!keyValue.count(key)) return -1;
        auto it = locator[key];
        frequency[keyValue[key].second++].erase(it);
        frequency[keyValue[key].second].push_front(key);
        locator[key] = frequency[keyValue[key].second].begin();
        if(frequency[minFreq].empty()) minFreq++;
        return keyValue[key].first;
        
    }
    
    void put(int key, int value) {
        if(cap <= 0) return;
        if(get(key) != -1){
            keyValue[key].first = value;
        }else{
            if(keyValue.size() == cap){
                int temp = frequency[minFreq].back();
                frequency[minFreq].pop_back();
                locator.erase(temp);
                keyValue.erase(temp);
            }
            keyValue[key] = {value, 1};
            frequency[1].push_front(key);
            locator[key] = frequency[1].begin();
            minFreq = 1;
        }
    }
private:
    int cap, minFreq;
    unordered_map> keyValue;
    unordered_map> frequency;
    unordered_map::iterator> locator;
};

简单一点的solution,不O(1), 但是省掉了一个HashMap,直接用list.remove(key)

class LFUCache {
public:
    LFUCache(int capacity) {
        this->capacity = capacity;
    }
    
    int get(int key) {
        if(!keyValue.count(key)) return -1;
        frequency[keyValue[key].second++].remove(key);
        frequency[keyValue[key].second].push_front(key);
        if(frequency[minFreq].empty()) minFreq++;
        return keyValue[key].first;
    }
    
    void put(int key, int value) {
        if(capacity <= 0) return;
        if(get(key) != -1){
            keyValue[key].first = value;
        }
        else{
            if(keyValue.size() == capacity){
                int temp = frequency[minFreq].back();
                frequency[minFreq].pop_back();
                keyValue.erase(temp);
            }
            keyValue[key] = {value, 1};
            frequency[1].push_front(key);
            minFreq = 1;
        }
    }
private:
    int capacity, minFreq = 0;
    unordered_map> keyValue;
    unordered_map> frequency;
};

你可能感兴趣的:(LRU & LFU Cache (Leetcode 146, Leetcode 460))