[Leetcode Solution] LRU Cache

来源:互联网 发布:php基本环境配置 编辑:程序博客网 时间:2024/06/05 16:16

LRU, also known as "Least Recently Used", is a cache algorithm which discards the the least recently used entry when we push a new entry to the cache.


This problem wants us to implement two function "int get(int key)" and "void set(int key, int value)" which means to get a record and add a new record in the cache(if the cache is full, remove the least recently used one). The hardest part is how to track which record is used and when.


I have implemented two version of solutions which both can get an "Accepted". 

The first one uses std::map and std::list to track the records. The std::map contains the pair of <key, pointer_to_value>, at the same time, the std::list stores the values and the list is ordered by the recent used time.


class LRUCache{public:    struct Entry {        int key, value;        Entry(){}        Entry(int ikey, int ivalue): key(ikey), value(ivalue) {}    };    LRUCache(int icap): capacity(icap) {}        int get(int key) {        if (mp.find(key) == mp.end()) {            return -1;        }        int res = mp[key] -> value;        move_front(key);        return res;    }    void set(int key, int value) {        if (mp.find(key) != mp.end()) {            mp[key] -> value = value;            move_front(key);        } else {            Entry res(key, value);            if (lst.size() >= capacity) {                pop_back();            }            lst.push_front(res);            mp[key] = lst.begin();        }    }    private:    map<int, list<Entry>::iterator> mp;    list<Entry> lst;    int capacity;        void move_front(int key) {        //ASSERT_NE(mp.find(key), mp.end())        Entry e = *mp[key];        auto iter = mp[key];        lst.erase(iter);        lst.push_front(e);        mp[key] = lst.begin();    }        void pop_back() {        Entry e = *(--lst.end());        mp.erase(e.key);        lst.pop_back();    }};

The second version only use one std::map the maintain all these record by implementing a double-linked list of the nodes of std::map, of course the list is sorted by the recent used time. Each node in the std::map contains a "previous" and a "next" record to indicate the key of the adjacent node in the list. And we also need a top/bottom pointer to indicate the first and last node of the list.


However, the second version is more complicated that I won't use that code in the interview.


class LRUCache {public:    LRUCache(int icap);    int get(int key);    void set(int key, int value);    void show();private:    struct entry {        int value, pre, next;        entry(){}        entry(int ivalue, int ipre, int inext): \                value(ivalue), pre(ipre), next(inext){}    };    void cache_remove(int key);    void cache_add(int key, int value);        size_t cap;    map<int, entry> mp;    int top, buttom;    static const int INVALID = -1;};LRUCache::LRUCache(int icap): cap(icap){    top = buttom = INVALID;    mp.clear();}void LRUCache::show(){    int now = top;    while (now != INVALID) {        auto iter = mp.find(now);        printf("<%d, %d>", now, (iter -> second).value);        now = (iter -> second).next;    }    puts("");}void LRUCache::cache_remove(int key){    if (key == INVALID) {        return;    }        auto iter = mp.find(key);    int pre = (iter -> second).pre;    int next = (iter -> second).next;    if (pre != INVALID) {        (mp.find(pre) -> second).next = next;    }    if (next != INVALID) {        (mp.find(next) -> second).pre = pre;    }    if (key == buttom) {        buttom = pre;    }    if (key == top) {        top = next;    }        mp.erase(iter);}void LRUCache::cache_add(int key, int value){    entry e(value, INVALID, top);    (mp.find(top) -> second).pre = key;    mp.insert(make_pair<int, entry>(int(key), entry(e)));    if (mp.size() > this -> cap) {        cache_remove(buttom);    }    top = key;    if (mp.size() == 1) {        this -> buttom = key;    }}int LRUCache::get(int key){    if (mp.find(key) == mp.end()) {        return -1;    }    int value = (mp.find(key) -> second).value;    cache_remove(key);    cache_add(key, value);    return value;  }void LRUCache::set(int key, int value){    if (mp.find(key) != mp.end()) {        cache_remove(key);    }    cache_add(key, value);}

The time complexity of the algorithm is as same as the get/set function of the std::map. 

0 0
原创粉丝点击