leetcode: LRU(最近最少使用)算法

                                                               True life is lived when tiny changes occur.  -- 列夫 托爾斯泰


前幾天看到了這個題目,隨然沒有仔細看細節,但是知道了這種思想,對我的幫助非常大。

leetcode鏈接:https://leetcode.com/problems/lru-cache/:

討論區裏的一種解法:kick me ,借鑑這種方法,自己修改後:

思路:

1) 作者的關於爲什麼採用list這種結構 的解釋: the good thing about lists is that iterators are never invalidated by modifiers (unless erasing the element itself). This way, we can store the iterator to the corresponding LRU queue in the values of the hash map. Since using erase on a list with an iterator takes constant time, all operations of the LRU cache run in constant time.

2)整體思路:用list來保存一個個節點,每個節點都是一個鍵值pair。然後,list的頭部總是保存最近被操作過的節點。但是,要從list中刪除元素,如果採用遍歷的方法,十分地耗時,因此再使用一個map將list中各個節點的對應的iterator(相當於地址)進行保存,這樣刪除時就不用進行遍歷了。 list中進行添加節點時,只是list的頭部進行添加,因此很快。

code:

class LRUCache {
public:
    LRUCache(int capacity) : _capacity(capacity) {}

    int get(int key) {
        auto it = cache.find(key);
        if (it == cache.end())
            return -1;

        touch(it->second,it->second->second);//it->first是map的key值哦
        return it->second->second;
    }

    void put(int key, int value) {
        auto it = cache.find(key);
        if (it != cache.end()){
            touch(it->second,value);
        }
        else {

            if (cache.size() == _capacity) {
                cache.erase(used.back().first);
                used.pop_back();
            }
            Pair_KeyVal pair(key,value);
            used.push_front(pair);
            cache[key] =  used.begin();
        }
    }

private:
    typedef pair<int, int> Pair_KeyVal;
    //定義一種list,其每一個節點都是一個 key-val pair
    //用list的原因在於可以控制在其頭尾進行操作,頭部是最近剛操縱過的
    typedef list<Pair_KeyVal> List_KeyValPair; 

    //定義一個unordered_map,其key值爲list的節點的key值,其val爲list的節點的iterator(相當於將list節點的地址保存下來)
    //使用unordered_map可以首先快速檢索。 
    typedef unordered_map<int, List_KeyValPair::iterator> Map_Key_ListIter;

    void touch(List_KeyValPair::iterator it,int setVal) {

        int key = it->first;
        used.erase(it);
        Pair_KeyVal pair(key,setVal);
        used.push_front(pair);

        cache[key] = used.begin();
    }

    Map_Key_ListIter cache;
    List_KeyValPair used;
    int _capacity;
};

關於c++中的map:

hash_map未加入在C++11標準中,因此使用了unordered_map。

c++ map內部實現了一個紅黑樹,該結構具有自動排序的功能,因此map內部的所有元素都是有序的,紅黑樹的每一個節點都代表着map的一個元素,因此,對於map進行的查找,刪除,添加等一系列的操作都相當於是對紅黑樹進行這樣的操作,故紅黑樹的效率決定了map的效率。


c++  unordered_map內部實現了一個哈希表,因此其元素的排列順序是雜亂的,無序的。 優點:因爲內部實現了哈希表,因此其查找速度非常快。對於查找問題,unordered_map會更加高效一些。 https://zh.cppreference.com/w/cpp/container/unordered_map


這種思想的一種簡單場景:- interview

實現一個文本編輯器,可以實現插入,撤銷操作。其中,撤銷操作需要你保存最近操作過的字符,當用戶點擊撤銷鍵時,將其最近添加或刪除的一個字符進行回退!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章