参考:
https://leetcode-cn.com/problems/lru-cache/solution/lruhuan-cun-ji-zhi-by-leetcode-solution/
LRU算法
1.双向链表+HashMap实现
参考题解:
https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/
import java.util.HashMap;
import java.util.Map;
public class Solution146 {
}
class LRUCache{
Map<Integer, DoubleLinkedNode> cache = new HashMap<>();
private int capacity;
private int size;
// 使用伪头部和伪尾部节点
private DoubleLinkedNode head;
private DoubleLinkedNode tail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.size = 0;
head = new DoubleLinkedNode();
tail = new DoubleLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key){
DoubleLinkedNode node = cache.get(key);
//如果key不存在就返回-1
if (node == null){
return -1;
}
// 如果 key 存在,先通过哈希表定位,再移到头部
moveToHead(node);
return node.value;
}
public void put(int key, int value){
//先根据key得到node
DoubleLinkedNode node = cache.get(key);
//如果node为空
if(node == null){
//新建一个节点
DoubleLinkedNode newNode = new DoubleLinkedNode(key, value);
//将新节点添加到头部
addToHead(newNode);
//缓存中记录该节点
cache.put(key, newNode);
//节点数量加1
size++;
//如果节点数量已大于缓存容量
if(size > capacity){
//删除末尾结点
DoubleLinkedNode tailNode = removeTailNode();
//同时在cache中删除key,由于tailNode记录了key和value,所以这里删除key可以用O(1)的时间达到
cache.remove(tailNode.key);
//结点数量减1
size--;
}
}else {
//如果节点不为空,就修改结点的值并移动到头部
node.value = value;
moveToHead(node);
}
}
/*
双向链表
*/
class DoubleLinkedNode{
//双向链表的前驱节点
DoubleLinkedNode prev;
//双向链表的后继节点
DoubleLinkedNode next;
//双向链表记录key和value
private int key;
private int value;
public DoubleLinkedNode() {
}
public DoubleLinkedNode(int key, int value) {
this.key = key;
this.value = value;
}
}
//双向链表的基本操作
//①在头部插入节点
public void addToHead(DoubleLinkedNode node){
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
//②删除结点
public void removeNode(DoubleLinkedNode node){
node.prev.next = node.next;
node.next.prev = node.prev;
}
//③将移动到头部可以等价为删除该节点后再将该节点插入到头部
public void moveToHead(DoubleLinkedNode node){
removeNode(node);
addToHead(node);
}
//④删除尾部结点
public DoubleLinkedNode removeTailNode(){
//tail为空。tail的前驱节点
DoubleLinkedNode res = tail.prev;
//删除该节点
removeNode(res);
return res;
}
}
2.LinkedHashMap实现
参考题解:
https://leetcode-cn.com/problems/lru-cache/solution/yuan-yu-linkedhashmapyuan-ma-by-jeromememory/
class LRUCache extends LinkedHashMap<Integer, Integer>{
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<Integer, Integer> eldest) {
return size() > capacity;
}
}
LinkedHashMap
/**
* //调用父类HashMap的构造方法。
* Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
* with the default initial capacity (16) and load factor (0.75).
*/
public LinkedHashMap() {
super();
accessOrder = false;
}
// 这里的 accessOrder 默认是为false,如果要按读取顺序排序需要将其设为 true
// initialCapacity 代表 map 的 容量,loadFactor 代表加载因子 (默认即可)
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}