LRU Cache

update Aug 22, 2017 22:30

LintCodearrow-up-right LeetCodearrow-up-right

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

  • get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.

  • put(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.

Follow up: Could you do both operations in O(1) time complexity?

Example:

        LRUCache cache = new LRUCache( 2 /* capacity */ );

        cache.put(1, 1);
        cache.put(2, 2);
        cache.get(1);       // returns 1
        cache.put(3, 3);    // evicts key 2
        cache.get(2);       // returns -1 (not found)
        cache.put(4, 4);    // evicts key 1
        cache.get(1);       // returns -1 (not found)
        cache.get(3);       // returns 3
        cache.get(4);       // returns 4

Basic Idea:

要实现一个O(1)时间完成get和set操作的 LRU cache 数据结构。以下分析摘自这里arrow-up-right

  • LRU,也就是least recently used,最近使用最少的;这样一个数据结构,能够保持一定的顺序,使得最近使用过的时间或者顺序被记录,实际上,具体每一个item最近一次何时被使用的,并不重要,重要的是在这样的一个结构中,item的相对位置代表了最近使用的顺序;满足这样考虑的结构可以是链表list或者数组array,不过前者更有利于insert和delete的操纵,此外,需要记录这个链表的head和tail,方便进行移动到tail或者删除head的操作,即:head.next作为最近最少使用的item,tail.prev为最近使用过的item,在set时,如果超出capacity,则删除head.next,同时将要插入的item放入tail.prev, 而get时,如果存在,只需把item更新到tail.prev即可。

  • 这样set与get均为O(1)时间的操作 (HashMap Get/Set + LinkedList Insert/Delete),空间复杂度为O(n), n为capacity。

实现过程中要注意使用模块化的思路,写removeNode和insertAtTail两个helper function使代码看上去更易读。

Python Code:

这段代码曾在LintCode的环境下ac;

Java Code:

This code got AC in LeetCode;

update 2018-10-11 18:24:22

Update: Java 最终版本

update Feb 21 2019, 22:45

Java 真最终版本

这次将维持size的函数分离出来,叫做ensureCapacity(),似的主要逻辑构架非常清晰明了。

update Aug 24, 2019

C++ 版本

注意在c++中实现链表我们需要内存管理,这里因为所有node都在map中,我们使用unordered_map<int, unique_ptr<ListNode>> 来管理heap上node的内存。

Last updated