leetcode No146. LRU Cache

Question

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.

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 in O(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

Algorithm

题意是让设计一个LRU缓存置换算法,LRU页面置换算法是操作系统里的内容,见:
http://blog.csdn.net/u011391629/article/details/54616468

Ex:拿题目例子说明,缓存大小为2
第一步:放1,1
那么此时缓存里(最近使用的在最右)(null,null)(1,1)
第二步:放2,2
因为最近使用的是2,2;那么此时缓存为(1,1)(2,2)
第三步:要用key为1的页面(使用过了,所以放最右,并返回value),此时缓存为(2,2)(1,1)
第四步:放3,3
因为容器大小只有2个,所以要删除一个,根据LRU原则,置换最长未使用的页面即原缓存中最左的2,2,然后把3,3放最右
此时缓存就为(1,1)(3,3)
依次类推。。。

具体实现摘自:
http://blog.csdn.net/qq508618087/article/details/50995188
思路: 这题的大致思路就是用一个hash表来保存已经存在的key, 然后用另外一个线性容器来存储其key-value值, 我们可以选择链表list, 因为需要调整结点的位置, 而链表可以在O(1)时间移动结点的位置, 数组则需要O(n).

如果新来一个set请求, 我们先去查hash表

  1. 如果已经存在了这个key, 那么我们需要更新其value, 然后将其在list的结点位置移动到链表首部.

  2. 如果不存在这个key, 那么我们需要在hash表和链表中都添加这个值, 并且如果添加之后链表长度超过最大长度, 我们需要将链表尾部的节点删除, 并且删除其在hash表中的记录

如果来了一个get请求, 我们仍然先去查hash表, 如果key存在hash表中, 那么需要将这个结点在链表的中的位置移动到链表首部.否则返回-1.

另外一个非常关键的降低时间复杂度的方法是在hash中保存那个key在链表中对应的指针, 我们知道链表要查找一个结点的时间复杂度是O(n), 所以当我们需要移动一个结点到链表首部的时候, 如果直接在链表中查询那个key所对于的结点, 然后再移动, 这样时间复杂度将会是O(n), 而一个很好的改进方法是在hash表中存储那个key在链表中结点的指针, 这样就可以在O(1)的时间内移动结点到链表首部.

c++的stl库提供非常丰富的函数, 掌握这些东西将会让代码长度大大减小.

Accepted Code

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

    int get(int key) {
        auto it=hash.find(key);
        if(it==hash.end())
            return -1;
        cache.splice(cache.begin(),cache,it->second);  //把key所在的迭代器放在list开头
        return it->second->second;
    }

    void put(int key, int value) {
        auto it=hash.find(key);
        if(it!=hash.end())
        {
            it->second->second=value;
            cache.splice(cache.begin(),cache,it->second);  //把key所在的迭代器放在list开头
            return;
        }
        cache.insert(cache.begin(),make_pair(key,value));
        hash[key]=cache.begin();
        if(cache.size() > size)
        {
            hash.erase(cache.back().first);
            cache.pop_back();
        }
    }
private:
    unordered_map<int,list<pair<int,int>>::iterator> hash;   //key 和 在list中迭代器的位置
    list<pair<int,int>> cache;   //存储页面的容器
    int size;
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值