146. LRU Cache

Design and implement a data structure forLeast Recently Used (LRU) cache. It should support the following operations:getandput.

get(key)- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value)- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

Follow up:
Could you do both operations inO(1)time complexity?

Example:

LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4

S: list + hashmap

用list存储key-value的关系,list从头到尾代表其节点被使用时间的关系,头结点是最近被使用的节点,尾节点是很久没使用的节点。

因为当list满了时删除操作也要删除hashmap里对应的节点,所以list需要存储key,仅有value是不行的。

用hashmap存储key到list节点(iterator)的关系,以实现O(1)的查找效率

注意每次更新要同步更新hashmap和list

class LRUCache {
public:
    LRUCache(int capacity) {
      cap = capacity;
    }

    int get(int key) {
      if (keyToListNode.find(key) == keyToListNode.end()) {
        return -1;
      }
      updateKey(key);
      return keyValueList.begin()->second;     
    }

    void put(int key, int value) {
        if (keyToListNode.find(key) != keyToListNode.end()) {
          updateKey(key);
          keyValueList.begin()->second = value;
        } else {
          if (keyValueList.size() == cap) {
            keyToListNode.erase(keyValueList.back().first);
            keyValueList.pop_back();
          }
          keyValueList.push_front(make_pair(key, value));
          keyToListNode[key] = keyValueList.begin();
        }
    }

private:
    list<pair<int, int>> keyValueList;
    unordered_map<int, list<pair<int, int>>::iterator> keyToListNode;
    int cap;
    void updateKey(int key) {      
      auto listIt = keyToListNode[key];
      keyValueList.push_front(make_pair(listIt->first, listIt->second));
      keyValueList.erase(listIt);
      keyToListNode[key] = keyValueList.begin();
    }
};

460. LFU Cache

Design and implement a data structure forLeast Frequently Used (LFU)cache. It should support the following operations:getandput.

get(key)- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value)- Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the leastrecentlyused key would be evicted.

Follow up:
Could you do both operations inO(1)time complexity?

Example:

LFUCache cache = new LFUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.get(3);       // returns 3.
cache.put(4, 4);    // evicts key 1.
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4

S: hashmap + list

对每个frequency用一个list存储对应的key, 从到后存储,需要删除时删除list.front()

用minFreq记录当前最小的frequency,当删除某一frequency时minFrequency增加,当插入新元素时minFreq重置为1

每次更新要同步更新所有存储结构

class LFUCache {
public:
    LFUCache(int capacity) {
        cap = capacity;
        size = 0;
        minFreq = 1;
    }

    int get(int key) {
        if (keyToValFreq.find(key) == keyToValFreq.end()) return -1;
        int val = keyToValFreq[key].first;
        int freq = keyToValFreq[key].second;
        updateKeyFreq(key, freq);
        return val;
    }

    void put(int key, int value) {
        if (keyToValFreq.find(key) == keyToValFreq.end()) {
            keyToValFreq[key] = make_pair(value, 1);
            addKeyFreq(key, 1);        
            size++;
            if (size > cap) {
                int delKey = *freqToKey[minFreq].begin();
                freqToKey[minFreq].pop_front();
                keyToValFreq.erase(delKey);
                keyToListIt.erase(delKey);      
                size--;
            }
            minFreq = 1;
        } else {
            int oldFreq = keyToValFreq[key].second;        

            keyToValFreq[key].first = value;
            updateKeyFreq(key, oldFreq);
        }

     }
private:
    int cap;
    int size;
    int minFreq;
    unordered_map<int, list<int>> freqToKey;
    unordered_map<int, pair<int, int>> keyToValFreq; //对每个key,存储对应的value和frequency, 方便快速定位到它对应的freqToKey list
    unordered_map<int, list<int>::iterator> keyToListIt; //iterator是key在freqToKey list中的位置,方便删除
    void updateKeyFreq(int key, int freq) {
        freqToKey[freq].erase(keyToListIt[key]);
         if (freqToKey[freq].empty()) {
            freqToKey.erase(freq);
            if (freq == minFreq) minFreq++;
        }
        keyToValFreq[key].second++;
        addKeyFreq(key, freq + 1);
    }

    void addKeyFreq(int key, int freq) {
        if (freqToKey.find(freq) == freqToKey.end()) {
            freqToKey[freq] = list<int>{key};                
        } else {
            freqToKey[freq].push_back(key);
        }
        keyToListIt[key] = --freqToKey[freq].end();
    }
};
·            ······BBBBBBBB

results matching ""

    No results matching ""