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?

题意:实现一个LRU缓存

Solution: HashMap + doubly LinkedList

删除操作分为2种情况:

  • 给定node data删除node: 单链表和双向链表都需要从头到尾进行遍历从而找到对应node进行删除,时间复杂度都为O(n)。
  • 给定node address删除node: 单链表需要从头到尾遍历直到找到该node的pre node,时间复杂度为O(n)。双向链表只需O(1)时间即能找到该node的pre node。

HashMap保存node address,可以基本保证在O(1)时间内找到该node

具体实现如下:

put(1,1):   先create 一个newNode(1,1)地址为$Node@435,HashMap存入(1, $Node@435),  双向链表将newNode(1,1)设为head

put(2,2):   先create 一个newNode(2,2)地址为$Node@436,HashMap存入(2, $Node@436),  双向链表将newNode(2,2)设为head

get(1):   先在HashMap中找到1对应node的地址$Node@435,通过该地址找到双向链表对应node(1,1) 。删除该node(1,1)再重新setHead

put(3,3):   先create 一个newNode(3,3)地址为$Node@437, 发现Cache is full! We need to evict something to make room.

1.  首先释放HashMap空间,通过双向链表中tailNode的key找到要在HashMap中删除的key

2.  然后删掉双向链表的tailNode

3.  将newNode(3,3)在双向链表中setHead

思考:

1. why not using java.util.LinkedinList?

因为java自带的linkedlist中,删除操作是从头到尾scan特定值再删除,时间为O(n)。但题目要求O(1)。

2. why not using java.util.LinkedHashMap?
这题说白了,就是考察java自带的LinkedHashMap是怎么实现的,我们当然不能。

code

 public class LRUCache {
private int capacity;
private final HashMap<Integer, Node> map;
private Node head;
private Node tail; public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
} public int get(int key) {
// no key exists
if (!map.containsKey(key)) return -1;
// key exists, move it to the front
Node n = map.get(key);
remove(n);
setHead(n);
return n.value; } public void put(int key, int value) {
// key exits
if (map.containsKey(key)) {
// update the value
Node old = map.get(key);
old.value = value;
// move it to the front
remove(old);
setHead(old);
}
// no key exists
else {
Node created = new Node(key, value);
// reach the capacity, move the oldest item
if (map.size() >= capacity) {
map.remove(tail.key);
remove(tail);
setHead(created);
}
// insert the entry into list and update mapping
else {
setHead(created);
}
map.put(key, created);
}
} private void remove(Node n) {
if (n.prev != null) {
n.prev.next = n.next;
} else {
head = n.next;
}
if (n.next != null) {
n.next.prev = n.prev;
} else {
tail = n.prev;
} } private void setHead(Node n) {
n.next = head;
n.prev = null;
if (head != null) head.prev = n;
head = n;
if (tail == null) tail = head;
} // doubly linked list
class Node {
int key;
int value;
Node prev;
Node next; public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
}

[leetcode]146. LRU CacheLRU缓存的更多相关文章

  1. Java实现 LeetCode 146 LRU缓存机制

    146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  2. leetcode 146. LRU Cache 、460. LFU Cache

    LRU算法是首先淘汰最长时间未被使用的页面,而LFU是先淘汰一定时间内被访问次数最少的页面,如果存在使用频度相同的多个项目,则移除最近最少使用(Least Recently Used)的项目. LFU ...

  3. [LeetCode] 146. LRU Cache 最近最少使用页面置换缓存器

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  4. [Leetcode]146.LRU缓存机制

    Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...

  5. [LeetCode] 146. LRU Cache 近期最少使用缓存

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  6. LeetCode 146. LRU缓存机制(LRU Cache)

    题目描述 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (k ...

  7. Leetcode 146. LRU 缓存机制

    前言 缓存是一种提高数据读取性能的技术,在计算机中cpu和主内存之间读取数据存在差异,CPU和主内存之间有CPU缓存,而且在内存和硬盘有内存缓存.当主存容量远大于CPU缓存,或磁盘容量远大于主存时,哪 ...

  8. Java for LeetCode 146 LRU Cache 【HARD】

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  9. leetcode@ [146] LRU Cache (TreeMap)

    https://leetcode.com/problems/lru-cache/ Design and implement a data structure for Least Recently Us ...

随机推荐

  1. [UE4]OnComponentBeginOverlap.AddDynamic 的编译错误

    以 Character 类为例,假设有 PacManCharacter 派生自 Character类首先在 PacManCharacter.h 头文件中添加碰撞函数的声明: OnCollision 为 ...

  2. sqoop操作之Oracle导入到HDFS

    导入表的所有字段 sqoop import --connect jdbc:oracle:thin:@192.168.1.100:1521:ORCL \ --username SCOTT --passw ...

  3. 经典算法 KMP算法详解

    内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...

  4. python入门第0篇 Windows下python的安装及pip安装和使用

    知识内容: 1. python2和python3安装 2. pip安装及pip命令使用 注:安装python3就可以了,python2除非项目开发需要否则不用安装,目前学习python就使用pytho ...

  5. python知识点, float不能用 != 判断

    python知识点链接:https://github.com/taizilongxu/interview_python 搜索:python最佳事件 书单:http://lucida.me/blog/d ...

  6. Delphi 解析HTML

    uses mshtml; IHTMLEleMent.ID; IHTMLEleMent.tagName; IHTMLEleMent.title;elmt._className;elmt.getAttri ...

  7. jd-eclipse反编译插件的在线安装和使用

    jd-eclipse反编译插件的在线安装和使用 JD-Eclipse是一个Eclipse平台的插件.它允许您调试所有的Java源代码,有了它,以后调试的时候ctrl键就可以一键到底啦.下面简单说说ec ...

  8. 使用Travis进行持续集成

    使用Travis进行持续集成 廖雪峰 持续集成:Continuous Integration,简称CI,意思是,在一个项目中,任何人对代码库的任何改动,都会触发CI服务器自动对项目进行构建,自动运行测 ...

  9. VBA 操作 VBE

    Introduction You can write code in VBA that reads or modifies other VBA projects, modules, or proced ...

  10. Java LinkList遍历方式

    1.LinkedList的遍历方式 a.一般的for循环(随机访问) int size = list.size(); for (int i=0; i<size; i++) { list.get( ...