LRU

  • LRU:Least Recently Used 最近最少使用
  • 題目要求:
    ? ? 設(shè)計(jì)和構(gòu)建一個(gè)“最近最少使用”緩存穷躁,該緩存會(huì)刪除最近最少使用的項(xiàng)目墅垮。緩存應(yīng)該從鍵映射到值(允許你插入和檢索特定鍵對(duì)應(yīng)的值)齿梁,并在初始化時(shí)指定最大容量痹扇。當(dāng)緩存被填滿時(shí)橡羞,它應(yīng)該刪除最近最少使用的項(xiàng)目患整。
    ? ? 它應(yīng)該支持以下操作: 獲取數(shù)據(jù) get 和 寫入數(shù)據(jù) put 拜效。
    ? ? 獲取數(shù)據(jù) get(key) - 如果密鑰 (key) 存在于緩存中,則獲取密鑰的值(總是正數(shù))各谚,否則返回 -1紧憾。寫入數(shù)據(jù) put(key, value) - 如果密鑰不存在,則寫入其數(shù)據(jù)值昌渤。當(dāng)緩存容量達(dá)到上限時(shí)赴穗,它應(yīng)該在寫入新數(shù)據(jù)之前刪除最近最少使用的數(shù)據(jù)值,從而為新的數(shù)據(jù)值留出空間膀息。

思路1:

  • KV操作一般想到的就是Map般眉。
  • LRU應(yīng)該有排序功能,最熱數(shù)據(jù)放最左潜支,冷數(shù)據(jù)經(jīng)過更迭就會(huì)滯后甸赃,map滿了每次剔除最后的數(shù)據(jù)即可。HashMap是無序的冗酿,需要加入順序埠对,第一個(gè)想到的肯定是LinkedHashMap。
  • 因?yàn)長inkedHashMap.put順序是結(jié)尾插入已烤,刪除也需要從頭結(jié)點(diǎn)遍歷鸠窗,所以正好修改思路以頭結(jié)點(diǎn)定為最冷數(shù)據(jù)、結(jié)尾定為最熱數(shù)據(jù)胯究。
  • put:分三種情況
    • map里存在key,但還需要修改為最熱數(shù)據(jù)躁绸,所以需要先remove后put即可裕循。
    • map里不存在key臣嚣,并且容量不滿,直接put即可剥哑。
    • map里不存在key硅则,并且容量滿,刪除最冷數(shù)據(jù)株婴,put即可怎虫。
  • get:
    • get就是不存在key就返回-1,存在就先remove后put變?yōu)樽顭釘?shù)據(jù)即可困介。
  • 調(diào)試后代碼:
class LRUCache {
  private Map<Integer, Integer> map;
    private int capacity;
    public LRUCache(int capacity) {
        map = new LinkedHashMap<>(capacity);
        this.capacity = capacity;
    }

    public int get(int key) {
        if(!map.containsKey(key)) {
            return -1;
        }
        int value = map.get(key);
        map.remove(key);
        map.put(key, value);
        return value;
    }

    public void put(int key, int value) {
        if(map.containsKey(key)){
            map.remove(key);
        }else if(map.size() == capacity){
            Integer removeKey = map.entrySet().iterator().next().getKey();
            map.remove(removeKey);
        }
        map.put(key, value);
    }
}
  • 運(yùn)行結(jié)果:
執(zhí)行用時(shí): 36 ms
內(nèi)存消耗: 46.6 MB

思路2(看官方答案后):

  • 官方說不能使用自帶的LinkedHashMap大审,只能用基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)。
  • 思路相同座哩,不過只能用HashMap和List實(shí)現(xiàn)了徒扶,效率沒有優(yōu)化,直接貼代碼根穷。
public class LRUCache {
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
        public DLinkedNode() {}
        public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
    }

    private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
    private int size;
    private int capacity;
    private DLinkedNode head, tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        // 使用偽頭部和偽尾部節(jié)點(diǎn)
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            return -1;
        }
        // 如果 key 存在姜骡,先通過哈希表定位,再移到頭部
        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            // 如果 key 不存在屿良,創(chuàng)建一個(gè)新的節(jié)點(diǎn)
            DLinkedNode newNode = new DLinkedNode(key, value);
            // 添加進(jìn)哈希表
            cache.put(key, newNode);
            // 添加至雙向鏈表的頭部
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                // 如果超出容量圈澈,刪除雙向鏈表的尾部節(jié)點(diǎn)
                DLinkedNode tail = removeTail();
                // 刪除哈希表中對(duì)應(yīng)的項(xiàng)
                cache.remove(tail.key);
                --size;
            }
        }
        else {
            // 如果 key 存在,先通過哈希表定位尘惧,再修改 value士败,并移到頭部
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(DLinkedNode node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(DLinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void moveToHead(DLinkedNode node) {
        removeNode(node);
        addToHead(node);
    }

    private DLinkedNode removeTail() {
        DLinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市褥伴,隨后出現(xiàn)的幾起案子谅将,更是在濱河造成了極大的恐慌,老刑警劉巖重慢,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饥臂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡似踱,警方通過查閱死者的電腦和手機(jī)隅熙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來核芽,“玉大人囚戚,你說我怎么就攤上這事≡颍” “怎么了驰坊?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哮独。 經(jīng)常有香客問我拳芙,道長察藐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任舟扎,我火速辦了婚禮分飞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘睹限。我一直安慰自己譬猫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布羡疗。 她就那樣靜靜地躺著染服,像睡著了一般。 火紅的嫁衣襯著肌膚如雪顺囊。 梳的紋絲不亂的頭發(fā)上肌索,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音特碳,去河邊找鬼诚亚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛午乓,可吹牛的內(nèi)容都是我干的站宗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼益愈,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼梢灭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蒸其,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤敏释,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后摸袁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钥顽,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年靠汁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蜂大。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝶怔,死狀恐怖奶浦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情踢星,我是刑警寧澤澳叉,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響耳高,放射性物質(zhì)發(fā)生泄漏扎瓶。R本人自食惡果不足惜所踊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一泌枪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秕岛,春花似錦碌燕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至遏考,卻和暖如春慈鸠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灌具。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國打工青团, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咖楣。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓督笆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親诱贿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娃肿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 緩存概述 在 Android 開發(fā)的過程中常常需要用到緩存的功能來減少應(yīng)用對(duì)用戶流量的消耗(如圖片緩存,文章緩存等...
    N0tExpectErr0r閱讀 792評(píng)論 0 3
  • 146. LRU緩存 設(shè)計(jì)和實(shí)現(xiàn)一個(gè)LRU(最近最少使用)的緩存機(jī)制珠十。它可以支持以下操作: get 和 put 料扰。...
    路得自己走閱讀 214評(píng)論 0 0
  • 點(diǎn)擊查看原題——146. LRU緩存機(jī)制 運(yùn)用你所掌握的數(shù)據(jù)結(jié)構(gòu),設(shè)計(jì)和實(shí)現(xiàn)一個(gè) LRU (最近最少使用) 緩存...
    小胖學(xué)編程閱讀 452評(píng)論 0 7
  • 運(yùn)用你所掌握的數(shù)據(jù)結(jié)構(gòu)焙蹭,設(shè)計(jì)和實(shí)現(xiàn)一個(gè) LRU (最近最少使用) 緩存機(jī)制晒杈。它應(yīng)該支持以下操作: 獲取數(shù)據(jù) ge...
    風(fēng)暴小狼閱讀 481評(píng)論 0 1
  • 題目: 運(yùn)用你所掌握的數(shù)據(jù)結(jié)構(gòu),設(shè)計(jì)和實(shí)現(xiàn)一個(gè) LRU (最近最少使用) 緩存機(jī)制壳嚎。它應(yīng)該支持以下操作: 獲取數(shù)...
    AceCream佳閱讀 315評(píng)論 0 2