zoukankan      html  css  js  c++  java
  • LRU Cache 题解

    题意

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

    get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
    set(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.

    这道题的题意就是说,使用LRU Cache,就是将最新使用的放置在前面,以便下次取的时候方便,其余则依次往下移动;

    思路

    其实我也是根据别人的想法做的,用链表加入值,因为链表对于往前往后添加或者删除都非常方便,但是有个麻烦的地方在于,我并不知知道他的位置在哪里,只能循环去找,因此我使用了一个哈希数组进行存储她的key和下标;

    实现

    我的实现(比较白痴)

    struct Node {
        int key;
        int value;
        Node(int _k, int _v) {key = _k; value = _v;}
    };
    
    class LRUCache{
    public:
        unordered_map<int, int> maps;
        list<Node> lists;
        int size;
        LRUCache(int capacity) {
            size = capacity;
        }
        
        /**
         *  获取值,同时获取也算是一种访问
         *
         *  @param key <#key description#>
         *
         *  @return <#return value description#>
         */
        int get(int key) {
            if (maps.size() == 0) {
                return -1;
            }
            if (maps.find(key) != maps.end()) {
                auto key_value = maps.find(key);
                int j = 0;
                for (auto itr = lists.begin(); itr != lists.end() && j < lists.size(); itr++, j++) {
                    if (j == key_value->second) {
                        int value = (*itr).value;
                        lists.push_front(Node((*itr).key, (*itr).value));
                        // 更新lists和maps
                        lists.erase(itr);
                        
                        // 将要更新的迭代器之前的下标都要加上1,其余的位置不需要改变
                        for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                            if (mitr->second < key_value->second){
                                mitr->second++;
                            }
                        }
                        
                        // 更新全部位置
                        key_value->second = 0;
                        
                        return value;
                    }
                }
            }
            return -1;
        }
        
        /**
         *  添加新值,不过需要注意的是当内存不够的情况下,需要删除掉最不经常使用的
         *
         *  @param key   <#key description#>
         *  @param value <#value description#>
         */
        void set(int key, int value) {
            if (lists.size() == size) {
                // 满了先进行删除
                list<Node>::iterator lend = --lists.end();
                lists.pop_back();
                
                int lkey = lend->key;
                maps.erase(maps.find(lkey));
                
                lists.push_front(Node(key, value));
                
                for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                    mitr->second++;
                }
                
                maps.insert(make_pair(key, 0));
            }
            else {
                // 存在的话
                if (maps.find(key) != maps.end()) {
                    auto key_value = maps.find(key);
                    maps[key] = 0;
                    for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                        if (mitr->second < key_value->second){
                            mitr->second++;
                        }
                    }
                    // 更新全部位置
                    key_value->second = 0;
                }
                else {
                    lists.push_front(Node(key, value));
                    for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                        mitr->second++;
                    }
                    maps.insert(make_pair(key, 0));
                }
            }
        }
    };
    
    
    int main(int argc, const char * argv[]) {
        // insert code here...
        LRUCache cache(5);
        cache.set(1, 10);
        cache.set(2, 20);
        cache.set(3, 30);
        
        //cout << "cache..." << cache.get(2) << endl;
        
        cache.set(4, 40);
        cache.set(5, 50);
        
        cache.set(8, 80);
        
        //cout << "cache..." << cache.get(1) << endl;
        cout << "cache..." << cache.get(5) << endl;
        
        return 0;
    }
    
    

    如上面所说,我需要不停的去更新其的位置,这样才能根据正确的位置去获取到具体的结点信息;根据题目的要求,需要控制时间复杂度在1,所以需要需要一个哈希数组去记录其位置;但是我好像并没有做到,依旧使用了一个循环。。。

    我的基础上优化

    struct node{
        int key;
        int value;
        node(int k, int v):key(k), value(v){}
    };
    
    /*
     * 注意整体思路是,使用双向list每次set或get一个元素时都把这个元素放到list的头部,无需统计每个元素的操作次数,实际上LRU的意思
     * 就是根据元素最后被访问的时间来决定替换哪个,故list中尾部元素即被替换.
     * STL技巧:1、使用map的find方法来判断key是否已经存在,返回值和map的end迭代器比较;
                2、使用unordered_map,它是hash_map,存取时间都是O(1),用它存储元素的position迭代器,是为了方便splice函数调用
     *          list.splice(position, list, element_pos)函数作用是把list的element_pos处的元素插入到position位置,本题中
                为了移动元素到list头部
     */
    class LRUCache{
        int size;
        list<node> values;
        unordered_map<int, list<node>::iterator> positions;
    public:
        LRUCache(int capacity) {
            size = capacity;
        }
        
        int get(int key) {
            if(positions.find(key) != positions.end()){
                values.splice(values.begin(), values, positions[key]);
                positions[key] = values.begin();
                
                return values.begin()->value;
            }
            return -1;
        }
        
        void set(int key, int value) {
            if(positions.find(key) != positions.end()){
                values.splice(values.begin(), values, positions[key]);  //移动被访问元素到头部
                values.begin()->value = value;
                positions[key] = values.begin();  //更新其位置,注意此处的position只是一个指针,当此key在list中被挤到其他位置后,positions里保存的位置也会跟着变化,因为它仅仅是一个指向该结点的指针       
            }
            else if(values.size()<size){
                values.push_front(node(key, value));
                positions[key] = values.begin();
            }
            else{
                node last = values.back();
                values.pop_back();
                positions.erase(last.key);
                
                values.push_front(node(key, value));
                positions[key] = values.begin();
            }
        }
        
    };
    
    

    将我的int下标,改成了纪录链表的迭代器,这下使用了splice会很方便,同时控制了时间复杂度。

    总结

    并没有。

  • 相关阅读:
    【贪心】【堆】Gym
    【并查集】Gym
    【拓扑排序】【bitset】Gym
    【递归】【线段树】【堆】AtCoder Regular Contest 080 E
    【二分图】【并查集】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem L. Canonical duel
    【动态规划】【滚动数组】【bitset】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem J. Terminal
    【二分】【字符串哈希】【二分图最大匹配】【最大流】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem I. Minimum Prefix
    【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game
    【推导】【构造】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem E. Space Tourists
    【推导】【贪心】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem D. Clones and Treasures
  • 原文地址:https://www.cnblogs.com/George1994/p/6287549.html
Copyright © 2011-2022 走看看