【算法】【LRU】146. LRU缓存机制

Description

设计和实现一个LRU(最近最少使用)缓存数据结构,使它应该支持以下操作: getput

get(key) - 如果密钥存在于缓存中,则获取密钥的值(值总是正数),否则返回 -1。
put(key, value) - 如果密钥不存在,请设置或插入值。当缓存达到其容量时,它应该在插入新项目之前使最近最少使用的项目作废。

后续:
你是否可以在 O(1) 时间复杂度中进行两种操作?

案例:

LRUCache cache = new LRUCache( 2 /* 容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 该操作,会将 key 2 作废
cache.get(2);       // 返回 -1 (结果不存在)
cache.put(4, 4);    // 该操作,会将 key 1 作废
cache.get(1);       // 返回 -1 (结果不存在)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

Solution

思路

  • list<pair<int, int>> (key, value)存在list中。
  • unordered_map<int, list<pair<int, int>>::iterator> 存储key和key所在的list的位置。
  • 链表头是最近使用过的元素。每当执行put(key, value)get(key)操作,把(key, value)插入链表头。
  • 链表尾是最久未读过的元素,当超过存储上限时,首先删掉链表尾和map对应的元素。

易错点

  • get(key)操作也会让链表中的key放到链表头。
  • put(key, value),若map中本来就存了key,则应替换成新的value,链表中的(key, value)放到链表头;而不应该删除链表尾的元素及其在map中的值。

代码

Leetcode accepted

class LRUCache {
private:
    int cap;
    int count;
    unordered_map<int, list<pair<int, int>>::iterator> m;
    list<pair<int, int>> queue;

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

    int get(int key) {
        int res = -1;
        auto p = m.find(key);
        if (p != m.end()) {
            res = p->second->second;
            queue.erase(p->second);
            queue.push_front(make_pair(key, res));
            p->second = queue.begin();
        }
        return res;
    }

    void put(int key, int value) {
        auto p = m.find(key);
        if (p != m.end()) {
            queue.erase(p->second);
        }
        else if (count == cap) {
            int delkey = queue.back().first;
            queue.pop_back();
            m.erase(delkey);
        }
        else {
            ++count;
        }
        queue.push_front(make_pair(key, value));
        m[key] = queue.begin();
    }
};
阅读更多
文章标签: LRU
个人分类: 算法分析与设计
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭