LRU緩存機(jī)制
運(yùn)用你所掌握的數(shù)據(jù)結(jié)構(gòu)霎箍,設(shè)計(jì)和實(shí)現(xiàn)一個(gè) LRU (最近最少使用) 緩存機(jī)制 贫奠。
實(shí)現(xiàn) LRUCache 類:
LRUCache(int capacity) 以正整數(shù)作為容量 capacity 初始化 LRU 緩存
int get(int key) 如果關(guān)鍵字 key 存在于緩存中舱权,則返回關(guān)鍵字的值逾冬,否則返回 -1 包吝。
void put(int key, int value) 如果關(guān)鍵字已經(jīng)存在锥余,則變更其數(shù)據(jù)值腹纳;如果關(guān)鍵字不存在,則插入該組「關(guān)鍵字-值」驱犹。當(dāng)緩存容量達(dá)到上限時(shí)嘲恍,它應(yīng)該在寫入新數(shù)據(jù)之前刪除最久未使用的數(shù)據(jù)值,從而為新的數(shù)據(jù)值留出空間雄驹。
進(jìn)階:你是否可以在 O(1) 時(shí)間復(fù)雜度內(nèi)完成這兩種操作佃牛?
示例:
輸入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
輸出
[null, null, null, 1, null, -1, null, -1, 3, 4]
解釋
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 緩存是 {1=1}
lRUCache.put(2, 2); // 緩存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 該操作會使得關(guān)鍵字 2 作廢,緩存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 該操作會使得關(guān)鍵字 1 作廢医舆,緩存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
思路:
一個(gè)hash俘侠,一個(gè)鏈表
代碼:
import java.util.HashMap;
public class LRUCache {
//當(dāng)前節(jié)點(diǎn)個(gè)數(shù)
private int curNum=0;
//最大節(jié)點(diǎn)個(gè)數(shù)
private int maxNum;
//一個(gè)鏈表
private LRUNode head=null;
//一個(gè)指向鏈表尾部節(jié)點(diǎn)的指針
private LRUNode tail=null;
private HashMap<Integer,LRUNode> map =new HashMap<>();
public LRUCache(int capacity) {
this.maxNum=capacity;
}
public int get(int key) {
if(map.containsKey(key)){
//如果當(dāng)前大小為1或者查詢的是頭節(jié)點(diǎn),那么直接返回
if(map.get(key)==head||curNum==1){
return map.get(key).value;
}
LRUNode temp=map.get(key);
LRUNode prevNode=temp.prev;
LRUNode nextNode=temp.next;
//如果當(dāng)前查詢的節(jié)點(diǎn)是尾節(jié)點(diǎn)蔬将,那么需要更改尾節(jié)點(diǎn)爷速,否則不需要修改
if(temp==tail){
tail=temp.prev;
tail.next=null;
temp.next=head;
head.prev=temp;
head=temp;
return temp.value;
}
else{
prevNode.next=nextNode;
nextNode.prev=prevNode;
if(prevNode.prev==null){
prevNode.prev=temp;
}
temp.next=head;
//更改頭節(jié)點(diǎn)
head.prev=temp;
head=temp;
return temp.value;
}
}
else{return -1;}
}
public void put(int key, int value) {
//查詢的節(jié)點(diǎn)已存在
if(this.get(key)!=-1){
//此時(shí)查詢的節(jié)點(diǎn)已經(jīng)是頭節(jié)點(diǎn)
head.value=value;
}
//新節(jié)點(diǎn)
else{
LRUNode node =new LRUNode(null,null,key,value);
map.put(key,node);
if(curNum==0){
head=node;
tail=node;
curNum++;
}
else if(curNum==1&&maxNum==1){
map.remove(tail.key);
head=node;
tail=node;
}
//當(dāng)前不為空
else{
//判斷是否達(dá)到緩存是否已滿
if(curNum==maxNum){
map.remove(tail.key);
tail=tail.prev;
tail.next=null;
head.prev=node;
node.next=head;
head=node;
}
else{node.next=head;
head.prev=node;
head=node;
curNum++;
}
}
}
}
class LRUNode{
LRUNode prev;
LRUNode next;
int key;
int value;
LRUNode(LRUNode prev,LRUNode next,int key,int value){
this.prev=prev;
this.next=next;
this.key=key;
this.value=value;
}
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/