運用你所掌握的數據結構,設計和實現一個 LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。
獲取數據 get(key) - 如果密鑰 (key) 存在於緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果密鑰已經存在,則變更其數據值;如果密鑰不存在,則插入該組「密鑰/數據值」。當緩存容量達到上限時,它應該在寫入新數據之前刪除最久未使用的數據值,從而爲新的數據值留出空間。
你是否可以在 O(1) 時間複雜度內完成這兩種操作?
來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/lru-cache 著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
主要思想: 利用HashMap和鏈表構建LRU,新訪問的節點放在鏈表的末尾,最久未使用的節點訪問頭部
class LRUCache {
// 記錄當前存儲了多少個鍵值對
private int size = 0;
// 初始容量
private int capacity = 0;
// 方便快速定位節點
Map<Integer,Node> cache = null;
// 頭結點
private Node head = null;
// 尾結點
private Node tail = null;
public LRUCache(int capacity) {
head = new Node(-1);
tail = new Node(-1);
head.post = tail;
tail.pre = head;
this.capacity = capacity;
size = 0;
cache = new HashMap<>();
}
public int get(int key) {
Node tem = cache.get(key);
if (tem!=null) {
moveToTail(tem); // 表明新訪問的節點在最後
return tem.value;
}
return -1;
}
public void put(int key, int value) {
Node tem = cache.get(key);
if (tem==null){ //沒找到節點,則新增節點
tem = new Node();
tem.key = key;
tem.value = value;
cache.put(key,tem);
addToTail(tem); //增加到最後
size++;
if (size>capacity){ //超出容量則刪除最近沒有訪問的節點,也就是頭結點
Node h = removeHead();
cache.remove(h.key);
size--;
}
}else{
tem.value = value;
moveToTail(tem);
}
}
//當前節點移動到尾部
private void moveToTail(Node tem){
Node pre = tem.pre;
Node next = tem.post;
pre.post = next;
next.pre = pre;
tem.post = tail;
tem.pre = tail.pre;
tail.pre.post = tem;
tail.pre = tem;
}
// 在尾部新增節點
private void addToTail(Node tem){
tem.post = tail;
tem.pre = tail.pre;
tail.pre.post = tem;
tail.pre = tem;
}
//刪除頭部最近沒有被訪問的節點
private Node removeHead(){
Node tem = head.post;
head.post = head.post.post;
head.post.pre = head;
return tem;
}
}
class Node{
int value;
int key;
Node pre;
Node post;
Node(int x){value = x;}
Node(){}
}
使用LinkedHashMap實現LRU緩存機制
class LRUCache {
LinkedHashMap<Integer,Integer> cache = null;
private final int MAX_CACHE_SIZE;
private final float DEFAULT_LOAD_FACTORY = 1.0f;
public LRUCache(int capacity) {
MAX_CACHE_SIZE = capacity;
cache = new LinkedHashMap<Integer, Integer>(capacity, DEFAULT_LOAD_FACTORY, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > MAX_CACHE_SIZE;
}
};
}
public int get(int key) {
Integer tem = cache.get(key);
if (tem!=null) {
return tem;
}
return -1;
}
public void put(int key, int value) {
cache.put(key,value);
}
}