LeetCode || LRU Cache

來源:互聯網
上載者:User

標籤:leetcode

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演算法,容器滿了之後,有LRU替換規則,開始時我對LRU理解錯了,以為需要記錄每個元素被訪問的次數資訊,後來發現不需要,LRU替換的本質是替換掉最長時間沒被訪問的元素,set和get都算訪問操作,故解決方案是cache中的元素是有序的,按照其被訪問的時間排序,最新被訪問的元素在頭部(或尾部),替換時直接刪除尾部(或頭部)元素即可,如果不使用有序序列的話,那麼需要記錄每個元素最後被訪問的時間,替換時,遍曆整個序列,找到時間最久的替換掉,但是這樣會逾時。故應該保持序列有序。

按照題目要求,要實現get和set功能,為了滿足隨機儲存需求我們首先想到數組,如果用鏈表會有O(n)的訪問時間。然而又要維護 least used 隊列,常用的放在前面,用的少的放在後面。這就要求我們要對節點有好的刪除和插入操作,這個要求又讓我們想到鏈表,因為數組的刪除和插入是O(n)複雜度的。
那麼我們能不能維護一個資料結構使得訪問操作和插入刪除操作都是O(1)複雜度的呢?答案是肯定的。即使用list儲存元素,在頭部插入,尾部刪除,每次訪問元素時,把它移動到頭部(雙向鏈表中移動一個元素到頭部時間複雜度是O(1));再用一個hash_map記錄元素的位置。


困難:如何?在每一次訪問元素時,重新調整序列的順序,讓被訪問元素移動到頭部???

解決:STL中各種容器只有list能方便地調整順序,就是splice方法,它可以實現把某個list的某個位置的元素或者某個區間位置的元素插入到當前list中,當然如果二者是同一個list,那麼就是調整該list中某些元素的順序了。splice方法的介紹在這裡,由於其參數為位置迭代器iterator,故我們需要記錄元素key對應的迭代器資訊,可以使用map,但是由於map是平衡樹實現的有序的序列,故其存取時間複雜度為O(logN),由於我們無需有序,故使用hash_map即可,即unordered_map。


代碼如下:

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();        }    }    };


參考連結:

http://www.myexception.cn/program/1598814.html

http://www.cnblogs.com/x1957/p/3485053.html





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.