设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。
它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
示例:
LRUCache cache = new LRUCache( 2 );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
class LRUCache {
linkedHashMap map;
int capacity;
public LRUCache(int capacity) {
map = new linkedHashMap(capacity, 0.75f,true);
this.capacity = capacity;
}
public int get(int key) {
if (map.containsKey(key)){
return map.get(key);
}
return -1;
}
public void put(int key, int value) {
if (map.size() == capacity) {
Set> entries = map.entrySet();
Iterator> iterator = entries.iterator();
Map.Entry next = null;
if (iterator.hasNext()) {
next = iterator.next();
}
if (next != null) {
map.remove(next.getKey());
}
}
map.put(key,value);
}
}
发现自己的put 没有去检索当前map 里面是不是包含同样的key,这样的话,就不需要remove 掉一个元素。第二,发现自己对removeEldestEntry 方法不熟悉。
正确解决方法一:(偷懒)class LRUCache extends linkedHashMap方法二:{ private int capacity; public LRUCache(int capacity) { super(capacity, 0.75F, true); this.capacity = capacity; } public int get(int key) { return super.getOrDefault(key, -1); } public void put(int key, int value) { super.put(key, value); } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > capacity; } }
class LRUCache {
class Node{
public Node pre;
public Node nex;
public int value;
public Node(int value){
this.value = value;
}
}
//
Map map ;
Node head,tail;
int capacity;
public LRUCache(int capacity) {
map = new HashMap(capacity);
head = new Node(-1);
tail = new Node(-1);
head.nex = tail;
tail.pre = head;
this.capacity = capacity;
}
public int get(int key) {
// have
if (map.containsKey(key)) {
// find key
Node node = findKey(key);
//move to head
moveToFirst(node);
//get value
return (int) map.get(key);
}else {
// not contains return -1
return -1;
}
}
public void put(int key, int value) {
if (map.containsKey(key)) {
//find
Node node = findKey(key);
// to head
moveToFirst(node);
map.put(key,value);
}else {
if (map.size() > capacity) {
//remove last
Node pre = tail.pre;
Node node = pre.pre;
node.nex = tail;
tail.pre = node;
// put new
putNew(key, value);
map.remove(pre.value);
}else {
putNew(key, value);
}
}
}
private void putNew(int key, int value) {
// put new
Node node = new Node(key);
map.put(key, value);
//move to head
moveToFirst(node);
}
public Node findKey(int key){
// find key
Node cur = head.nex;
//linkedHashMap 也这样查找吗?
while (cur != null) {
if (cur.value == key) {
return cur;
}
cur = cur.nex;
}
return null;
}
public void moveToFirst(Node node){
//if is head
if (head.nex == node) {
return;
}
// 衔接node
if (node.pre != null){
Node pre1 = node.pre;
Node nex1 = node.nex;
pre1.nex = nex1;
nex1.pre = pre1;
}
Node pre = head.nex;
head.nex = node;
node.pre = head;
node.nex = pre;
pre.pre = node;
}
}
有点乱 写了一个小时才写出来
不好的地方在于 hasMap 的value 应该放Node
这样就不需要findKey
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 cache = new HashMap();
private int size;
private int capacity;
private DlinkedNode head, tail;
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
// 使用伪头部和伪尾部节点
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 不存在,创建一个新的节点
DlinkedNode newNode = new DlinkedNode(key, value);
// 添加进哈希表
cache.put(key, newNode);
// 添加至双向链表的头部
addToHead(newNode);
++size;
if (size > capacity) {
// 如果超出容量,删除双向链表的尾部节点
DlinkedNode tail = removeTail();
// 删除哈希表中对应的项
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;
}
}
思考:
1.写算法应该先写逻辑
// fink key
//return value
//…
保证每一步骤都不能少
比如此题
如果超过了容量
要从map里面remove 掉
不然就会有问题
2.写的每一行代码 写完要思考一下对不对
比如 >= 写成了> 结果可能就错了
你在每一行都思考一下
出了错误页不需要整个篇幅去排查问题了



