運用你所掌握的數據結構,設計和實現一個 LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。
獲取數據 get(key) - 如果關鍵字 (key) 存在於緩存中,則獲取關鍵字的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果關鍵字已經存在,則變更其數據值;如果關鍵字不存在,則插入該組「關鍵字/值」。當緩存容量達到上限時,它應該在寫入新數據之前刪除最久未使用的數據值,從而為新的數據值留出空間。
進階:
你是否可以在 O(1) 時間復雜度內完成這兩種操作?
示例:
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
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/lru-cache
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
實現思路:查找和插入的時間復雜度都需要是O(1),那么只能通過hash表+雙向鏈表的方式實現(LinkedHashMap就是這種方式),這里首先使用自定義的一個雙向鏈表進行實現。
private int headKey;
private int lastKey;
private Map<Integer,Node> map;
private int capacity;
public LRUCache(int capacity) {
headKey = -1;
lastKey = -1;
this.capacity = capacity;
map = new HashMap<>(capacity);
}
/**
* 將節點移動到尾節點
* @param n
*/
private void changeNodeToLast(Node n){
//判斷是否有頭節點
if(headKey == -1){
headKey = n.key;
}
//判斷當前節點是否是尾節點
if(lastKey == n.key){
return;
}
//判斷當前節點是否是頭節點
if(headKey == n.key){
//判斷當前是否只有一個節點
if(n.after == null){
return;
}
headKey = n.after.key;
}
Node b = n.before;
Node a = n.after;
//將當前節點移動到尾節點
if(b != null){
b.after = a;
}
if(a != null){
a.before = b;
}
Node last = map.get(lastKey);
lastKey = n.key;
n.before = last;
last.after = n;
last = n;
last.after = null;
}
/**
* 添加新節點
* @param key
* @return
*/
private Node addNewNode(int key){
Node n = new Node();
//是否有頭節點
if(headKey == -1){
headKey = key;
}
//是否有尾節點
else if(lastKey == -1){
lastKey = key;
Node head = map.get(headKey);
n.before = head;
head.after = n;
}else{
//中間節點處理
Node last = map.get(lastKey);
n.before = last;
last.after = n;
lastKey = key;
}
return n;
}
/**
* 移除頭節點
*/
private void removeNode(){
Node node = map.get(headKey);
map.remove(headKey);
if(node.after != null){
headKey = node.after.key;
node.after.before = null;
}else{
headKey = -1;
lastKey = -1;
}
}
public int get(int key) {
Node n = map.get(key);
if(n != null){
this.changeNodeToLast(n);
return n.value;
}
return -1;
}
public void put(int key, int value) {
Node n = map.get(key);
if(n == null){
if(map.size()>= capacity){
this.removeNode();
}
n = this.addNewNode(key);
n.key = key;
n.value = value;
map.put(key,n);
}else{
this.changeNodeToLast(n);
n.key = key;
n.value = value;
}
}
private class Node{
public Node before;
public int key ;
private int value;
private Node after;
public Node(){
key = -1;
value = -1;
}
}
力扣執行結果: