Open azl397985856 opened 1 year ago
# hashmap + doubly linked list
# hashmap key: key, value: doubly linked node
# create a doubly linked node class for convenience
class Node:
def __init__(self, key, val):
""" The node class store(key, val)
this Node is a doubly linked node,
so it should also initialize prev and next pointer
"""
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
#initialize a hashmap and a doubly linked list
self.cap = capacity
self.cache = {}
# initialize two nodes to define boundary
self.left = Node(0, 0) # lru
self.right = Node(0, 0) # mru
# generate doubly linked list
self.left.next = self.right
self.right.prev = self.left
def get(self, key: int) -> int:
"""" if key exists, return its value and insert it to mru node
if key not exists, return -1
"""
if key not in self.cache:
return -1
else:
self.remove(self.cache[key])
self.insert(self.cache[key])
return self.cache[key].val
def put(self, key: int, value: int) -> None:
""" if key exists, we need to remove and re-insert to mru
if key not exists, just insert to mru
we also need to deal with exceeding capacity situation
"""
if key in self.cache:
self.remove(self.cache[key])
# put to hashmap
self.cache[key] = Node(key, value)
self.insert(self.cache[key])
if len(self.cache) > self.cap:
# remove lru first
lru = self.left.next
self.remove(lru)
del self.cache[lru.key]
def insert(self, node: Node) -> None:
""" insert node before mru
example a <-> node <--> right
"""
prv = self.right.prev
prv.next = node
node.prev = prv
node.next = self.right
self.right.prev = node
def remove(self, node: Node) -> None:
""" remove node from a doubly linked list
example a <-> b <-> c
"""
prv = node.prev
nxt = node.next
prv.next = nxt
nxt.prev = prv
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
Space = O(N)
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.length = 0
self.capacity = capacity
def get(self, key: int) -> int:
if key in self.cache:
self.cache.move_to_end(key)
return self.cache[key]
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.cache[key] = value
self.cache.move_to_end(key)
else:
if self.length < self.capacity:
self.length += 1
else:
self.cache.popitem(False)
self.cache[key] = value
class Node:
def __init__(self, key, value, prev = None, nextNode = None):
self.key = key
self.value = value
self.prev = prev
self.next = nextNode
class LRUCache:
def __init__(self, capacity: int):
self.cache = {}
self.capacity = capacity
self.left = Node(0,0)
self.right = Node(0,0)
self.left.next = self.right
self.right.prev = self.left
def get(self, key: int) -> int:
if key in self.cache:
node = self.cache[key]
self.remove(node)
self.insert(node)
return node.value
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = Node(key, value)
self.remove(self.cache[key])
self.insert(node)
self.cache[key] = node
else:
if len(self.cache) == self.capacity:
self.remove(self.right.prev)
node = Node(key, value)
self.insert(node)
def remove(self, node):
prev = node.prev
after = node.next
prev.next = after
after.prev = prev
del self.cache[node.key]
def insert(self, node):
one = self.left.next
self.left.next = node
node.prev = self.left
node.next = one
one.prev = node
self.cache[node.key] = node
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
**函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。**
示例:
输入
["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); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
class Node:
def __init__(self, key, val):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.nums = 0
self.capacity = capacity
# lookup table, {key: key, value: node}
self.lookup = dict()
# doubly linkedlist, [head<->old_node<->new_node<->tail]
self.head = Node(None, None)
self.tail = Node(None, None)
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key: int) -> int:
if key not in self.lookup:
return -1
# 1. get the node
node = self.lookup[key]
# 2. remove node
self.remove(node)
# 3. add node to the tail
self.add_to_tail(node)
return node.val
def put(self, key: int, value: int) -> None:
# 1. remove the old node, if exist
if key in self.lookup:
self.remove(self.lookup[key])
self.nums -= 1
# 2. remove oldest node if full
if self.nums == self.capacity:
self.remove(self.head.next)
self.nums -= 1
# 3. add the node to the tail
self.add_to_tail(Node(key, value))
self.nums += 1
def remove(self, node):
# remove node from lookup and doubly linkedlist
del self.lookup[node.key]
node.prev.next = node.next
node.next.prev = node.prev
def add_to_tail(self, node):
# add node to lookup and the tail (before tail)
self.lookup[node.key] = node
pre_tail = self.tail.prev
node.next = self.tail
self.tail.prev = node
pre_tail.next = node
node.prev = pre_tail
class LRUCache {
public:
struct LRUNode
{
int key;
int val;
LRUNode* prev;
LRUNode* next;
LRUNode() : key(0), val(0), prev(nullptr), next(nullptr) {}
LRUNode(int _key, int _val) : key(_key), val(_val), prev(nullptr), next(nullptr) {}
};
LRUNode* front;
LRUNode* end;
int cap;
int nc;
unordered_map<int, LRUNode*> hash;
LRUCache(int capacity) {
front = new LRUNode();
end = new LRUNode();
front -> next = end;
end -> prev = front;
cap = capacity;
nc = 0;
}
int get(int key) {
int res = -1;
if (hash.count(key))
{
res = hash[key] -> val;
deleteFromlist(hash[key]);
addTofront(hash[key]);
}
return res;
}
void put(int key, int value) {
if (hash.count(key))
{
hash[key] -> val = value;
deleteFromlist(hash[key]);
addTofront(hash[key]);
}
else
{
if (nc == cap)
{
nc--;
hash.erase(end -> prev -> key);
deleteFromend();
}
nc++;
LRUNode* temp = new LRUNode(key, value);
addTofront(temp);
hash[key] = temp;
}
}
void addTofront(LRUNode* temp)
{
temp -> next = front -> next;
front -> next -> prev = temp;
front -> next = temp;
temp -> prev = front;
}
void deleteFromend()
{
LRUNode* temp = end -> prev;
temp -> prev -> next = end;
end -> prev = temp -> prev;
}
void deleteFromlist(LRUNode* p)
{
LRUNode* q = p -> prev;
q -> next = p -> next;
p -> next -> prev = q;
}
};
/**
* 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);
*/
使用 hash map 讓 get 可以 O(1) 使用雙向 linked list 讓刷新 key 最後使用順序,以及找出最不常用到的 key,都可以在 O(1) 完成
class LRUCache:
def __init__(self, capacity: int):
self.size = capacity
self.map = {}
self.head = ListNode(-1, -1)
self.tail = ListNode(-1, -1)
self.head.right = self.tail
self.tail.left = self.head
def get(self, key: int) -> int:
if key in self.map:
node = self.map[key]
# move to right side of the head
node.left.right = node.right
node.right.left = node.left
node.right = self.head.right
node.left = self.head
self.head.right.left = node
self.head.right = node
return node.val
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.map:
node = self.map[key]
# move to right side of the head
node.left.right = node.right
node.right.left = node.left
node.right = self.head.right
node.left = self.head
self.head.right.left = node
self.head.right = node
# update value
node.val = value
else:
if len(self.map) == self.size:
# evict the least recently used key
node = self.tail.left
del self.map[node.key]
self.tail.left = node.left
node.left.right = self.tail
# put new node
node = ListNode(key, value)
self.map[key] = node
node.left = self.head
node.right = self.head.right
self.head.right.left = node
self.head.right = node
return
class ListNode:
def __init__(self, key, val):
self.key = key
self.val = val
self.left = None
self.right = None
Time: O(1) Space: O(N), N = capacity
OrderedDict
时间复杂度:O(1) 空间复杂度:O(N)
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.size = capacity
def get(self, key: int) -> int:
if key not in self.cache:
return -1
value = self.cache.pop(key)
self.cache[key]=value
return value
def put(self, key: int, value: int) -> None:
if key not in self.cache and len(self.cache)>=self.size:
self.cache.popitem(last=False)
if key in self.cache:
self.cache.pop(key)
self.cache[key]=value
为使两个函数达到O(1)复杂度,同时使用链表和哈希表
struct ListNodes {
ListNodes* prev;
ListNodes* next;
int key, val;
ListNodes(): key(0), val(0), prev(nullptr), next(nullptr){}
ListNodes(int _key, int _value): key(_key), val(_value), prev(nullptr), next(nullptr){}
};
class LRUCache {
private:
unordered_map<int, ListNodes*> hashmap;
ListNodes* head;
ListNodes* tail;
int capacity, size;
public:
LRUCache(int _capacity): capacity(_capacity), size(0) {
head = new ListNodes();
tail = new ListNodes();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if(!hashmap.count(key))
return -1;
ListNodes* node = hashmap[key];
moveTohead(node);
return node->val;
}
void put(int key, int value) {
if(!hashmap.count(key)){
ListNodes* node = new ListNodes(key, value);
hashmap[key] = node;
addTohead(node);
++size;
if(size > capacity){
ListNodes* removed = removeTail();
hashmap.erase(removed->key);
--size;
delete removed;
}
}
else {
ListNodes* node = hashmap[key];
node->val = value;
moveTohead(node);
}
}
void addTohead(ListNodes* node){
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}
void removeNode(ListNodes* node){
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveTohead(ListNodes* node){
removeNode(node);
addTohead(node);
}
ListNodes* removeTail(){
ListNodes* node = tail->prev;
removeNode(node);
return node;
}
};
时间:O(1) 空间:O(N)
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.size = capacity;
//Map对象能够保留键的插入顺序
this.map = new Map();
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
let val = -1;
if (this.map.has(key)) {
val = this.map.get(key);
this.map.delete(key);
//重新插入 map,调整顺序
this.map.set(key, val);
}
return val;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if (this.map.has(key)) {
this.map.delete(key);
}
this.map.set(key, value);
if (this.map.size > this.size) {
//keys()返回一个迭代器对象,第一次调用 next 返回第一次被插入的数据
//此时为最近未使用过的数据
this.map.delete(this.map.keys().next().value);
}
};
class ListNode {
constructor(key, value) {
this.value = value;
this.key = key;
this.pre = null;
this.next = null;
}
}
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.max = capacity;
//记录key-node
this.map = new Map();
//虚拟头尾
this.head = new ListNode();
this.tail = new ListNode();
this.head.next = this.tail;
this.tail.pre = this.head;
this.moveToHead = (node) => {
this.removeNode(node);
this.appendToHead(node);
};
this.removeNode = (node) => {
const pre = node.pre;
const next = node.next;
pre.next = next;
next.pre = pre;
};
this.appendToHead = (node) => {
node.pre = this.head;
node.next = this.head.next;
this.head.next.pre = node;
this.head.next = node;
};
this.limit = () => {
if (this.map.size > this.max) {
const node = this.tail.pre;
this.removeNode(node);
this.map.delete(node.key);
}
};
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if (this.map.has(key)) {
const node = this.map.get(key);
this.moveToHead(node);
return node.value;
}
return -1;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if (this.map.has(key)) {
const node = this.map.get(key);
node.value = value;
this.moveToHead(node);
} else {
const node = new ListNode(key, value);
this.appendToHead(node);
this.map.set(key, node);
this.limit();
}
};
struct Node
{
int key;
int val;
Node* pre;
Node* next;
Node() : key(-1), val(0), pre(nullptr), next(nullptr) {}
Node(int _key, int _val) : key(_key), val(_val), pre(nullptr), next(nullptr) {}
};
class LRUCache {
private:
int size;
int m_capacity;
unordered_map<int, Node*> hashtable;
Node* head = new Node();
Node* tail = new Node();
private:
void moveHead(Node* node)
{
if (head->next == node)
{
return;
}
// cout << node->key << endl;
Node* nodePre = node->pre;
Node* headNext = head->next;
nodePre->next = node->next;
node->next->pre = nodePre;
head->next = node;
node->pre = head;
node->next = headNext;
headNext->pre = node;
}
void insertHead(Node* node)
{
Node* headNext = head->next;
head->next = node;
node->pre = head;
node->next = headNext;
headNext->pre = node;
}
void removeLast()
{
Node* del = tail->pre;
// cout << del->key << endl;
Node* delPre = del->pre;
delPre->next = tail;
tail->pre = delPre;
}
void print()
{
Node* p = head;
while (p)
{
cout << p->key << ' ';
p = p->next;
}
cout << endl;
}
public:
LRUCache(int capacity) {
size = 0;
m_capacity = capacity;
hashtable.clear();
// head
head->next = tail;
tail->pre = head;
}
int get(int key) {
// cout << key << endl;
if (hashtable.count(key))
{
Node* node = hashtable[key];
// cout << node->val << endl;
moveHead(node);
// cout << "success" << endl;
// print();
return node->val;
}
// print();
return -1;
}
void put(int key, int value) {
// cout << key << endl;
if (hashtable.count(key))
{
Node* node = hashtable[key];
node->val = value;
moveHead(node);
}
else
{
Node* newNode = new Node(key, value);
hashtable[key] = newNode;
if (size == m_capacity)
{
int delKey = tail->pre->key;
// cout << delKey << endl;
hashtable.erase(delKey);
removeLast();
}
else
{
++size;
}
insertHead(newNode);
}
// print();
}
};
""" 通过一个字典和链表来存储键值和顺序,通过设链表的头尾,用于链表指针的确定 """
class MyNode: def init(self, key=0, value=0): self.key = key self.value = value self.next = None self.prev = None
class LRUCache:
def __init__(self, capacity: int):
self.cashe = dict()
self.head = MyNode()
self.tail = MyNode()
self.head.next = self.tail
self.tail.prev = self.head
self.size = 0
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self.cashe:
return -1
node = self.cashe[key]
self.moveToHead(node)
return node.value
def put(self, key: int, value: int) -> None:
if key in self.cashe:
node = self.cashe[key]
node.value = value
self.moveToHead(node)
else:
node = MyNode(key, value)
self.cashe[key] = node
self.addToHead(node)
self.size+=1
if self.size>self.capacity:
removed = self.removeTail()
self.cashe.pop(removed.key)
self.size-=1
def removeNode(self,node):
node.prev.next = node.next
node.next.prev = node.prev
def addToHead(self,node):
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def moveToHead(self,node):
self.removeNode(node)
self.addToHead(node)
def removeTail(self):
node = self.tail.prev
self.removeNode(node)
return node
""" 时间复杂度:O(1) 空间复杂度:O(capacity) """
TC: get: O(1) put: O(1)
SC: O(n)
class LRUCache {
private final DLinkedList list;
private final Map<Integer, DLinkedList.DLinkedNode> map;
private final int capacity;
public LRUCache(int capacity) {
list = new DLinkedList();
map = new HashMap<>();
this.capacity = capacity;
}
public int get(int key) {
if (!map.containsKey(key)) return -1;
var node = map.get(key);
list.moveToHead(node);
return node.getVal();
}
public void put(int key, int value) {
if (map.containsKey(key)) {
var node = map.get(key);
node.setVal(value);
list.moveToHead(node);
return;
}
if (capacity == map.size())
map.remove(list.deleteTail().getKey());
var node = new DLinkedList.DLinkedNode(key, value);
map.put(key, node);
list.addHead(node);
}
}
class DLinkedList {
private final DLinkedNode dummyHead;
private final DLinkedNode dummyTail;
public DLinkedList() {
dummyHead = new DLinkedNode();
dummyTail = new DLinkedNode();
dummyHead.next = dummyTail;
dummyTail.prev = dummyHead;
}
public void moveToHead(DLinkedNode node) {
removeNode(node);
addHead(node);
}
public DLinkedNode deleteTail() {
var tail = dummyTail.prev;
removeNode(tail);
return tail;
}
public void addHead(DLinkedNode node) {
node.prev = dummyHead;
node.next = dummyHead.next;
dummyHead.next.prev = node;
dummyHead.next = node;
}
private void removeNode(DLinkedNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
public static class DLinkedNode {
private int key;
private int val;
private DLinkedNode prev;
private DLinkedNode next;
DLinkedNode() {
}
DLinkedNode(int key, int val) {
this.key = key;
this.val = val;
}
public int getKey() {
return key;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
}
}
//Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
//Use doubly LinkedList to implement get & put with O(1) time complexity
//Compared to singly linkedlist, the delete operation is pretty efficient, because we know current node's previous one
//In this LRU, we need HashMap to help us restore key & node, to help us easily find target.
//we need doubly linkedlist to help us record most & least recently used.
//use 4 helper functions: addToHead, deleteTail, removeNode, moveNodeToHead.
//remember when get/put, we need update not only doubly linkedlist but also hashMap.
// Time Complexity: O(1), Space Complexity:O(capacity)
class LRUCache {
class DNode {
DNode pre;
DNode next;
int val;
int key;
DNode() {
}
DNode(int key, int value) {
this.key = key;
this.val = value;
}
}
private HashMap<Integer, DNode> map = new HashMap<>();
private DNode dummHead;
private DNode dummTail;
private int size, capacity;
public LRUCache(int capacity) {
this.dummHead = new DNode();
this.dummTail = new DNode();
dummHead.next = dummTail;
dummTail.pre = dummHead;
this.size = 0;
this.capacity = capacity;
}
public int get(int key) {
DNode cur = map.get(key);
if (cur == null)
return -1;
moveNodeToHead(cur);
return cur.val;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
DNode cur = map.get(key);
cur.val = value;
moveNodeToHead(cur);
} else {
DNode newNode = new DNode(key, value);
map.put(key, newNode);
addToHead(newNode);
size++;
while (size > capacity) {
DNode res = deleteTail();
map.remove(res.key);
size--;
}
}
}
private void addToHead(DNode node) {
// DNode temp = dummHead.next;
node.pre = dummHead;
node.next = dummHead.next;
dummHead.next.pre = node;
dummHead.next = node;
}
private void removeNode(DNode node) {
node.pre.next = node.next;
node.next.pre = node.pre;
}
private void moveNodeToHead(DNode node) {
removeNode(node);
addToHead(node);
}
private DNode deleteTail() {
DNode res = dummTail.pre;
removeNode(res);
return res;
}
思路大混乱,照着lc和答案抄了一下+
class Node:
def __init__(self, key, val):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
# 构建双向链表首尾节点, 使之相连
self.head = Node(0, 0)
self.tail = Node(0, 0)
self.head.next = self.tail
self.tail.prev = self.head
# 记录位置
self.lookup = dict()
self.max_len = capacity
def get(self, key: int) -> int:
if key in self.lookup:
node = self.lookup[key]
self.remove(node)
self.add(node)
return node.val
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.lookup:
self.remove(self.lookup[key])
#满了要删掉了
if len(self.lookup) == self.max_len:
self.remove(self.head.next)
self.add(Node(key, value))
# 删除链表节点
def remove(self, node):
del self.lookup[node.key]
node.prev.next = node.next
node.next.prev = node.prev
# 加在链表尾
def add(self, node):
# 记录每个 key 对应的链表节点引用
self.lookup[node.key] = node
#+到尾巴之前
pre_tail = self.tail.prev
node.next = self.tail
self.tail.prev = node
pre_tail.next = node
node.prev = pre_tail
**复杂度分析**
- 时间复杂度:O(1),其中 N 为数组长度。
- 空间复杂度:O(N)
1、先了解lru是什么,Least Recently Used,题中意思可以简单理解为最新使用的数据放在最前面,老的数据往后排,或者我们直接淘汰掉
2、根据这个思想,那么我们可以做相关的设计,哈希+链表,首先判断数据是否在我们的lrucache里面,如果在,我们就把它放在第一位,剩下的还是按照原顺序组合,如果不在,我们就淘汰最末位,将新数据放在第一位,如此即可
class LRUCache {
class DLinkedNode {
int key, value;
DLinkedNode prev, next;
public DLinkedNode() {}
public DLinkedNode(int _key, int _value) {
key = _key;
value = _value;
}
}
private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
private int size, cap;
private DLinkedNode head, tail;
public LRUCache(int capacity) {
size = 0;
cap = capacity;
//add dummy head and dummyTail
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;
//if key exist, move it to head by using its location store in Hashmap
moveToHead(node);
return node.value;
}
public void put(int key, int value) {
DLinkedNode node = cache.get(key);
if (node == null) {
//made a newNode if it does not exist
DLinkedNode newNode = new DLinkedNode(key, value);
cache.put(key, newNode);
addToHead(newNode);
++size;
if (size > cap) {
DLinkedNode removedTail = removeTail();
cache.remove(removedTail.key);
--size;
}
} else {
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;
}
}
时间复杂度:O(1) 空间复杂度:O(n)
class LRUCache:
def __init__(self, capacity):
self.dic = collections.OrderedDict()
self.remain = capacity
def get(self, key):
if key not in self.dic:
return -1
v = self.dic.pop(key)
self.dic[key] = v # set key as the newest one
return v
def put(self, key, value):
if key in self.dic:
self.dic.pop(key)
else:
if self.remain > 0:
self.remain -= 1
else: # self.dic is full
self.dic.popitem(last=False)
self.dic[key] = value
type Node struct {
Key int
Value int
Next *Node
Prev *Node
}
type LRUCache struct {
Head *Node
Tail *Node
M map[int]*Node
Count int
Capacity int
}
func Constructor(capacity int) LRUCache {
head := &Node{}
tail := &Node{}
head.Next = tail
tail.Prev = head
return LRUCache{ Head: head, Tail: tail, M: make(map[int]*Node), Count: 0, Capacity: capacity }
}
func (this *LRUCache) removeNode(node *Node) {
node.Prev.Next, node.Next.Prev = node.Next, node.Prev
node.Prev, node.Next = nil, nil
}
func (this *LRUCache) insertToHead(node *Node) {
node.Next, node.Prev = this.Head.Next, this.Head
node.Prev.Next, node.Next.Prev = node, node
}
func (this *LRUCache) Get(key int) int {
node, ok := this.M[key]
if !ok {
return -1
}
value := node.Value
// move node to head
this.removeNode(node)
this.insertToHead(node)
return value
}
func (this *LRUCache) Put(key int, value int) {
node, ok := this.M[key]
if ok { // if key exist, update node and move to head
node.Value = value
this.removeNode(node)
this.insertToHead(node)
} else { // if key not exist, create a new node and insert to head
newNode := &Node{ Value: value, Key: key }
if this.Count >= this.Capacity {
lastNode := this.Tail.Prev
this.removeNode(lastNode)
delete(this.M, lastNode.Key)
this.Count -= 1
}
this.insertToHead(newNode)
this.M[key] = newNode
this.Count += 1
}
}
class ListNode:
def __init__(self, key=None, val=None):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
self.head = ListNode()
self.tail = ListNode()
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key: int) -> int:
if key in self.cache:
node = self.cache[key]
self.remove(node)
self.add_to_head(node)
return node.val
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
self.remove(node)
if len(self.cache) == self.capacity:
self.remove(self.head.next)
self.add_to_head(ListNode(key, value))
def remove(self, node):
del self.cache[node.key]
node.prev.next = node.next
node.next.prev = node.prev
def add_to_head(self, node):
self.cache[node.key] = node
pre_tail = self.tail.prev
node.next = self.tail
self.tail.prev = node
pre_tail.next = node
node.prev = pre_tail
class LRUCache {
int capacity, size;
Map<Integer, Node> map;
Node head, tail;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<> ();
head = new Node();
tail = new Node();
head.next = tail;
tail.pre = head;
}
public int get(int key) {
if (!map.containsKey(key)) {
return -1;
}
Node node = map.get(key);
Node preNode = node.pre, nextNode = node.next;
preNode.next = nextNode;
nextNode.pre = preNode;
Node headNext = head.next;
head.next = node;
node.next = headNext;
headNext.pre = node;
node.pre = head;
return node.value;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
get(key);
map.get(key).value = value;
return;
}
if (size == capacity) {
Node last = tail.pre;
last.pre.next = tail;
tail.pre = last.pre;
last.pre = null;
last.next = null;
map.remove(last.key);
size--;
put(key, value);
} else {
size++;
Node first = new Node();
first.key = key;
first.value = value;
Node next = head.next;
head.next = first;
first.pre = head;
first.next = next;
next.pre = first;
map.put(key, first);
}
}
class Node {
private int key;
private int value;
Node pre, next;
}
}
/**
* 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);
*/
doubly linked list+hashMap
class LRUCache {
Node head = new Node(0, 0), tail = new Node(0, 0);
Map<Integer, Node> map = new HashMap();
int capacity;
public LRUCache(int _capacity) {
capacity = _capacity;
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if(map.containsKey(key)) {
Node node = map.get(key);
remove(node);
insert(node);
return node.value;
} else {
return -1;
}
}
public void put(int key, int value) {
if(map.containsKey(key)) {
remove(map.get(key));
}
if(map.size() == capacity) {
remove(tail.prev);
}
insert(new Node(key, value));
}
private void remove(Node node) {
map.remove(node.key);
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void insert(Node node){
map.put(node.key, node);
Node headNext = head.next;
head.next = node;
node.prev = head;
headNext.prev = node;
node.next = headNext;
}
class Node{
Node prev, next;
int key, value;
Node(int _key, int _value) {
key = _key;
value = _value;
}
}
复杂度 时间:O(1) 空间:O(N)
class LRUCache {
class DoubleLinkedNode{
int key, value;
DoubleLinkedNode prev, next;
public DoubleLinkedNode(){}
public DoubleLinkedNode(int _key, int _value){
key = _key;
value = _value;
}
}
private Map<Integer, DoubleLinkedNode> cache = new HashMap<Integer, DoubleLinkedNode>();
private int size, cap;
private DoubleLinkedNode head, tail;
public LRUCache(int capacity) {
size = 0;
cap = capacity;
head = new DoubleLinkedNode();
tail = new DoubleLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
DoubleLinkedNode node = cache.get(key);
if(node == null){
return -1;
}
moveToHead(node);
return node.value;
}
public void put(int key, int value) {
DoubleLinkedNode node = cache.get(key);
if(node == null){
DoubleLinkedNode newNode = new DoubleLinkedNode(key, value);
cache.put(key, newNode);
addToHead(newNode);
++size;
if(size > cap){
DoubleLinkedNode removedTail = removeTail();
cache.remove(removedTail.key);
--size;
}
}
else{
node.value = value;
moveToHead(node);
}
}
private void addToHead(DoubleLinkedNode node){
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private void removeNode(DoubleLinkedNode node){
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void moveToHead(DoubleLinkedNode node){
removeNode(node);
addToHead(node);
}
private DoubleLinkedNode removeTail(){
DoubleLinkedNode res = tail.prev;
removeNode(res);
return res;
}
}
Time: O(1) Space: O(N)
双端链表和hash结构记录
时间复杂度O(1) 空间复杂度O(n)
class LRUCache {
Map<Integer, DoubleListNode> cache;
//ArrayList<DoubleListNode> keyList;
int max;
int len;
DoubleListNode head;
DoubleListNode tail;
public LRUCache(int capacity) {
cache = new HashMap<>(capacity);
//keyList = new ArrayList<>();
max = capacity;
head = tail = null;
len = 0;
}
public int get(int key) {
DoubleListNode ans = cache.get(key);
if(ans == null){
return -1;
}
moveToLast(ans);
return ans.getValue();
}
public void put(int key, int value) {
DoubleListNode doubleListNode = cache.get(key);
if (doubleListNode == null) {
DoubleListNode temp = new DoubleListNode(key, value);
if (max == len) {
DoubleListNode headTemp = head;
if (head == tail) {
head = tail = null;
} else {
head = head.getAfter();
head.setBefore(null);
headTemp.setAfter(null);
}
//keyList.remove(headTemp);
cache.remove(headTemp.getKey());
len--;
}
cache.put(key, temp);
moveToLast(temp);
len++;
// keyList.add(temp);
} else {
doubleListNode.setKeyValue(key, value);
moveToLast(doubleListNode);
}
}
private void moveToLast(DoubleListNode temp) {
//分四种情况
//新增的 前节点为尾节点 尾节点=这个节点
//头节点 下一个节点变为头节点 下一节点置空 前节点为尾节点 尾节点=这个节点
//尾节点 不动
//中间节点 记录前后节点 调转前后节点的指向 后节点置空 前节点为尾节点 尾节点=这个节点
if (temp.getBefore() == null) {
if (head == null) {
head = tail = temp;
return ;
}
if (temp.getAfter() != null) {
//头节点
head = head.getAfter();
head.setBefore(null);
temp.setAfter(null);
}
tail.setAfter(temp);
temp.setBefore(tail);
tail = temp;
}else {
if (temp.getAfter() != null) {
//中间节点
DoubleListNode after = temp.getAfter();
DoubleListNode before = temp.getBefore();
before.setAfter(after);
after.setBefore(before);
temp.setAfter(null);
tail.setAfter(temp);
temp.setBefore(tail);
tail = temp;
}
}
}
class DoubleListNode {
private DoubleListNode before;
private Integer key;
private Integer value;
private DoubleListNode after;
public DoubleListNode(Integer key, Integer value) {
this.key = key;
this.value = value;
this.before = null;
this.after = null;
}
public DoubleListNode(DoubleListNode before, Integer key, Integer value, DoubleListNode after) {
this.key = key;
this.value = value;
this.before = before;
this.after = after;
}
public DoubleListNode getBefore() {
return before;
}
public DoubleListNode getAfter() {
return after;
}
public void setAfter(DoubleListNode after) {
this.after = after;
}
public void setBefore(DoubleListNode before) {
this.before = before;
}
public Integer getKey() {
return key;
}
public Integer getValue() {
return value;
}
public void setKeyValue(Integer key, Integer value) {
this.key = key;
this.value = value;
}
}
}
struct DListNode{
int key, value;
DListNode* prev;
DListNode* next;
DListNode() : key(0), value(0), prev(nullptr), next(nullptr){}
DListNode(int _key, int _value):key(_key), value(_value),
prev(nullptr), next(nullptr){}
};
class LRUCache { private: unordered_map<int, DListNode> map; DListNode head; DListNode* tail; int size; int capacity;
public: LRUCache(int _capacity): capacity(_capacity), size(0){ head = new DListNode(); tail = new DListNode(); head->next = tail; tail->next = head; }
int get(int key) {
if(!map.count(key)){
return -1;
}
DListNode* node = map[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
if(!map.count(key)){
DListNode* node = new DListNode(key, value);
map[key] = node;
addToHead(node);
++size;
if(size > capacity){
DListNode* rm = removeTail();
map.erase(rm->key);
delete rm;
--size;
}
}
else{
DListNode* node = map[key];
node->value = value;
moveToHead(node);
}
}
void addToHead(DListNode* node){
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}
void removeNode(DListNode* node){
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveToHead(DListNode* node){
removeNode(node);
addToHead(node);
}
DListNode* removeTail(){
DListNode* node = tail->prev;
removeNode(node);
return node;
}
};
----
### 复杂度分析
- TC:(1)
- SC:(N)
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.capacity = capacity;
this.map = new Map();
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if(!this.map.has(key)) return -1;
const v = this.map.get(key);
//删掉再新加。
this.map.delete(key);
this.map.set(key, v);
return v;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
// 需要先判断是否存在。因为如果是满的情况且更新值的情况会删错。
if(this.map.get(key)) {
// 存在先删除
this.map.delete(key)
}
if(this.map.size >= this.capacity) {
// 删除最久未使用
// next().value 返回的是第一组键
this.map.delete(this.map.keys().next().value);
}
this.map.set(key, value)
};
/**
* Your LRUCache object will be instantiated and called as such:
* var obj = new LRUCache(capacity)
* var param_1 = obj.get(key)
* obj.put(key,value)
*/
class LRUCache {
struct Node{
int key;
int val;
Node* prev;
Node *next;
Node() {
}
Node(int k, int v) : key(k), val(v) {
}
};
unordered_map<int, Node*> m;
Node* head = nullptr;
Node* tail = nullptr;
int capacity_;
void addHead(Node* node) {
head->next->prev = node;
node->next = head->next;
node->prev = head;
head->next = node;
}
void deleteNode(Node* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}
public:
LRUCache(int capacity) {
capacity_ = capacity;
head = new Node;
tail = new Node;
head->next = tail;
tail->next = head;
head->prev = tail;
tail->prev = head;
}
int get(int key) {
if(m.count(key)) {
int res = m[key]->val;
Node *node = m[key];
deleteNode(node);
addHead(node);
return res;
}
return -1;
}
void put(int key, int value) {
if(m.count(key)) {
Node* node = m[key];
node->val = value;
deleteNode(node);
addHead(node);
return;
}
Node* node = new Node(key, value);
addHead(node);
m[key] = node;
if(m.size() > capacity_) {
Node* last = tail->prev;
m.erase(last->key);
deleteNode(last);
}
}
};
用list
来维护关键字的新旧, map
来记录关键字的键值对
class LRUCache {
private HashMap<Integer, Integer> map;
private ArrayList<Integer> list;
private int max;
public LRUCache(int capacity) {
max = capacity;
map = new HashMap<>();
list = new ArrayList<>();
}
public int get(int key) {
if (map.containsKey(key)) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == key) {
list.remove(i);
list.add(key);
break;
}
}
return map.get(key);
}
else return -1;
}
public void put(int key, int value) {
if (this.get(key) == -1) {
if (list.size() == max) {
int rm = list.get(0);
list.remove(0);
map.remove(rm);
}
list.add(key);
}
map.put(key, value);
}
}
复杂度分析
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.length = 0
self.capacity = capacity
def get(self, key: int) -> int:
if key in self.cache:
self.cache.move_to_end(key)
return self.cache[key]
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.cache[key] = value
self.cache.move_to_end(key)
else:
if self.length < self.capacity:
self.length += 1
else:
self.cache.popitem(False)
self.cache[key] = value
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.size = capacity;
this.map = new Map();
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
let val = -1;
if (this.map.has(key)) {
val = this.map.get(key);
this.map.delete(key);
this.map.set(key, val);
}
return val;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if (this.map.has(key)) {
this.map.delete(key);
}
this.map.set(key, value);
if (this.map.size > this.size) {
this.map.delete(this.map.keys().next().value);
}
};
var LRUCache = function(capacity) { this.size = capacity; this.map = new Map(); };
LRUCache.prototype.get = function(key) { let val = -1; if (this.map.has(key)) { val = this.map.get(key); this.map.delete(key); this.map.set(key, val); } return val; };
LRUCache.prototype.put = function(key, value) { if (this.map.has(key)) { this.map.delete(key); } this.map.set(key, value); if (this.map.size > this.size) { this.map.delete(this.map.keys().next().value); } };
需要一个hash表 和双向链表
public class LRUCache
{
Dictionary<int, int> dict;
LinkedList<int> nums;
int capacity;
public LRUCache(int capacity)
{
this.capacity = capacity;
dict = new Dictionary<int, int>();
nums = new LinkedList<int>();
}
public int Get(int key)
{
if (dict.ContainsKey(key))
{
nums.Remove(key);
nums.AddLast(key);
return dict[key];
}
return -1;
}
public void Put(int key, int value)
{
if (dict.ContainsKey(key))
{
nums.Remove(key);
nums.AddLast(key);
dict[key] = value;
}
else
{
if (nums.Count == capacity)
{
dict.Remove(nums.First.Value);
nums.RemoveFirst();
nums.AddLast(key);
dict.Add(key, value);
}
else
{
nums.AddLast(key);
dict.Add(key, value);
}
}
}
}
这个题目太好了。
算法思路
// put
if key 存在:
更新节点值
把节点移到链表头部
else:
if 缓存满了:
移除最后一个节点
删除它在哈希表中的映射
新建一个节点
把节点加到链表头部
在哈希表中增加映射
// get
if key 存在:
返回节点值
把节点移到链表头部
else:
返回 -1
class DoubleLinkedListNode {
constructor(key, value) {
this.key = key
this.value = value
this.prev = null
this.next = null
}
}
class LRUCache {
constructor(capacity) {
this.capacity = capacity
this.usedSpace = 0
// Mappings of key->node.
this.hashmap = {}
this.dummyHead = new DoubleLinkedListNode(null, null)
this.dummyTail = new DoubleLinkedListNode(null, null)
this.dummyHead.next = this.dummyTail
this.dummyTail.prev = this.dummyHead
}
_isFull() {
return this.usedSpace === this.capacity
}
_removeNode(node) {
node.prev.next = node.next
node.next.prev = node.prev
node.prev = null
node.next = null
return node
}
_addToHead(node) {
const head = this.dummyHead.next
node.next = head
head.prev = node
node.prev = this.dummyHead
this.dummyHead.next = node
}
get(key) {
if (key in this.hashmap) {
const node = this.hashmap[key]
this._addToHead(this._removeNode(node))
return node.value
}
else {
return -1
}
}
put(key, value) {
if (key in this.hashmap) {
// If key exists, update the corresponding node and move it to the head.
const node = this.hashmap[key]
node.value = value
this._addToHead(this._removeNode(node))
}
else {
// If it's a new key.
if (this._isFull()) {
// If the cache is full, remove the tail node.
const node = this.dummyTail.prev
delete this.hashmap[node.key]
this._removeNode(node)
this.usedSpace--
}
// Create a new node and add it to the head.
const node = new DoubleLinkedListNode(key, value)
this.hashmap[key] = node
this._addToHead(node)
this.usedSpace++
}
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* var obj = new LRUCache(capacity)
* var param_1 = obj.get(key)
* obj.put(key,value)
*/
待定
class LRUCache
{
public:
list<pair<int,int>> l;
unordered_map<int,list<pair<int, int>>::iterator> m;
int size;
LRUCache(int capacity)
{
size=capacity;
}
int get(int key)
{
if(m.find(key)==m.end())
return -1;
l.splice(l.begin(),l,m[key]);
return m[key]->second;
}
void put(int key, int value)
{
if(m.find(key)!=m.end())
{
l.splice(l.begin(),l,m[key]);
m[key]->second=value;
return;
}
if(l.size()==size)
{
auto d_key=l.back().first;
l.pop_back();
m.erase(d_key);
}
l.push_front({key,value});
m[key]=l.begin();
}
};
复杂度分析 待定
经典LRU算法
class LRUCache(object):
def __init__(self, capacity):
"""
:type capacity: int
"""
LRUCache.capacity = capacity
LRUCache.length = 0
LRUCache.dict = collections.OrderedDict()
def get(self, key):
"""
:rtype: int
"""
try:
value = LRUCache.dict[key]
del LRUCache.dict[key]
LRUCache.dict[key] = value
return value
except:
return -1
def put(self, key, value):
"""
:type key: int
:type value: int
:rtype: nothing
"""
try:
del LRUCache.dict[key]
LRUCache.dict[key] = value
except:
if LRUCache.length == LRUCache.capacity:
LRUCache.dict.popitem(last = False)
LRUCache.length -= 1
LRUCache.dict[key] = value
LRUCache.length += 1
class LRUCache {
private HashMap<Integer, Integer> map;
private ArrayList<Integer> list;
private int max;
public LRUCache(int capacity) {
max = capacity;
map = new HashMap<>();
list = new ArrayList<>();
}
public int get(int key) {
if (map.containsKey(key)) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == key) {
list.remove(i);
list.add(key);
break;
}
}
return map.get(key);
}
else return -1;
}
public void put(int key, int value) {
if (this.get(key) == -1) {
if (list.size() == max) {
int rm = list.get(0);
list.remove(0);
map.remove(rm);
}
list.add(key);
}
map.put(key, value);
}
}
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.cap = capacity
def get(self, key: int) -> int:
if key in self.cache:
self.cache.move_to_end(key)
return self.cache[key]
return -1
def put(self, key: int, value: int) -> None:
self.cache[key] = value
self.cache.move_to_end(key)
if len(self.cache)>self.cap:
self.cache.popitem(last=False)
为使两个函数达到O(1)复杂度,同时使用链表和哈希表
struct ListNodes {
ListNodes* prev;
ListNodes* next;
int key, val;
ListNodes(): key(0), val(0), prev(nullptr), next(nullptr){}
ListNodes(int _key, int _value): key(_key), val(_value), prev(nullptr), next(nullptr){}
};
class LRUCache {
private:
unordered_map<int, ListNodes*> hashmap;
ListNodes* head;
ListNodes* tail;
int capacity, size;
public:
LRUCache(int _capacity): capacity(_capacity), size(0) {
head = new ListNodes();
tail = new ListNodes();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if(!hashmap.count(key))
return -1;
ListNodes* node = hashmap[key];
moveTohead(node);
return node->val;
}
void put(int key, int value) {
if(!hashmap.count(key)){
ListNodes* node = new ListNodes(key, value);
hashmap[key] = node;
addTohead(node);
++size;
if(size > capacity){
ListNodes* removed = removeTail();
hashmap.erase(removed->key);
--size;
delete removed;
}
}
else {
ListNodes* node = hashmap[key];
node->val = value;
moveTohead(node);
}
}
void addTohead(ListNodes* node){
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}
void removeNode(ListNodes* node){
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveTohead(ListNodes* node){
removeNode(node);
addTohead(node);
}
ListNodes* removeTail(){
ListNodes* node = tail->prev;
removeNode(node);
return node;
}
};
时间:O(1) 空间:O(N)
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.dict = OrderedDict()
def get(self, key: int) -> int:
if key not in self.dict:
return -1
self.dict.move_to_end(key)
return self.dict[key]
def put(self, key: int, value: int) -> None:
if key in self.dict:
self.dict.move_to_end(key)
self.dict[key] = value
if len(self.dict) > self.capacity:
self.dict.popitem(last=False)
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.dict = OrderedDict()
def get(self, key: int) -> int:
if key not in self.dict:
return -1
self.dict.move_to_end(key)
return self.dict[key]
def put(self, key: int, value: int) -> None:
if key in self.dict:
self.dict.move_to_end(key)
self.dict[key] = value
if len(self.dict) > self.capacity:
self.dict.popitem(last=False)
采用哈希表,保证get操作在O(1)时间复杂度内完成,
构建双向链表,保证put操作在O(1)时间复杂度内完成
javaScript
var LinkedList = function(key, val) {
this.key = key;
this.val = val;
this.prev = null;
this.next = null;
}
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.capacity = capacity;
this.size = 0;
this.cache = new Map();
// 构建虚拟节点
this.dummyHead = new LinkedList();
this.dummyTail = new LinkedList();
this.dummyHead.next = this.dummyTail;
this.dummyTail.prev = this.dummyHead;
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if (!this.cache.has(key)) {
return -1;
}
const node = this.cache.get(key);
// 将节点移动至链表头部
this.removeNode(node);
this.appendToHead(node);
return node.val;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
// 判断关键字key是否存在于缓存中
const node = this.cache.get(key);
if (node) {
// 更新关键字的值
node.val = value;
this.cache.set(key, node);
// 将关键字移动至链表头部
this.removeNode(node);
this.appendToHead(node);
} else {
// 当缓存容量达到上限时
if (this.size === this.capacity) {
// 删除最久未使用的
this.removeTailNode();
}
// 创建新节点
const newNode = new LinkedList(key, value);
this.cache.set(key, newNode)
this.appendToHead(newNode);
this.size ++;
}
};
LRUCache.prototype.removeNode = function(node) {
let preNode = node.prev;
let nextNode = node.next;
preNode.next = nextNode;
nextNode.prev = preNode;
}
LRUCache.prototype.appendToHead = function(node) {
let head = this.dummyHead.next;
this.dummyHead.next = node;
node.prev = this.dummyHead;
node.next = head;
head.prev = node;
}
LRUCache.prototype.removeTailNode = function() {
this.size --;
let tailNode = this.dummyTail.prev;
this.cache.delete(tailNode.key);
this.removeNode(tailNode);
}
struct DLinkeNode{
int key, value;
DLinkeNode* prev;
DLinkeNode* next;
DLinkeNode(): key(0), value(0), prev(nullptr), next(nullptr){}
DLinkeNode(int key1, int value1): key(key1), value(value1), prev(nullptr), next(nullptr){}
};
class LRUCache {
private:
unordered_map<int,DLinkeNode*> mp;
DLinkeNode* head;
DLinkeNode* tail;
int max_capacity;
int size;
public:
void removeNode(DLinkeNode* node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
void addToHead(DLinkeNode* node)
{
node->next = head->next;
head->next = node;
node->prev = head;
node->next->prev = node;
}
void moveToHead(DLinkeNode* node)
{
removeNode(node);
addToHead(node);
}
LRUCache(int capacity) {
mp.clear();
max_capacity = capacity;
size = 0;
head = new DLinkeNode();
tail = new DLinkeNode();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if(mp.count(key)==0)
return -1;
DLinkeNode* node = mp[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
if(mp.count(key)==0)
{
DLinkeNode* node = new DLinkeNode(key,value);
mp[key] = node;
addToHead(node);
++size;
if(size>max_capacity)
{
DLinkeNode* temp = tail->prev;
tail->prev = temp->prev;
temp->prev->next = tail;
mp.erase(temp->key);
delete temp;
--size;
}
}
else
{
DLinkeNode* node = mp[key];
node->value = value;
moveToHead(node);
}
}
};
Below is my C++ solution using std::unordered_map
and std::list
.
Hope it helps ;-)
#include <unordered_map>
#include <list>
class LRUCache {
public:
LRUCache(int capacity) : capacity(capacity) {}
int get(int key) {
auto node = m.find(key);
if (node == m.end()) return -1;
// put the retrieved node to last
auto itr = node->second;
int value = itr->second;
nodes.erase(itr);
nodes.push_back({key, value});
m[key] = prev(nodes.end());
return value;
}
void put(int key, int value) {
// if key is existed, remove it from map
if (auto node = m.find(key); node != m.end()) {
nodes.erase(node->second);
}
// if capacity is reached, remove the first-to-kill node
if (nodes.size() >= capacity) {
int key_to_remove = nodes.front().first;
m.erase(m.find(key_to_remove));
nodes.pop_front();
}
// add new node
nodes.push_back({key, value});
m[key] = prev(nodes.end());
}
private:
using PII = pair<int, int>;
unordered_map<int, list<PII>::iterator> m; // store key -> ref to node
list<PII> nodes; // store node{key, value}
int capacity;
};
type entry struct { key, value int }
type LRUCache struct {
cap int
cache map[int]*list.Element
lst *list.List
}
func Constructor(capacity int) LRUCache {
return LRUCache{capacity, map[int]*list.Element{}, list.New()}
}
func (c *LRUCache) Get(key int) int {
e := c.cache[key]
if e == nil { return -1 }
c.lst.MoveToFront(e) // 刷新缓存使用时间
return e.Value.(entry).value
}
func (c *LRUCache) Put(key, value int) {
if e := c.cache[key]; e != nil {
e.Value = entry{key, value}
c.lst.MoveToFront(e) // 刷新缓存使用时间
return
}
c.cache[key] = c.lst.PushFront(entry{key, value})
if len(c.cache) > c.cap {
delete(c.cache, c.lst.Remove(c.lst.Back()).(entry).key)
}
}
var LRUCache = function(capacity) {
this.cap = capacity;
this.cache = {};
this.length = 0;
};
LRUCache.prototype.get = function(key) {
if(this.cache[key] != undefined) {
var temp = this.cache[key];
delete this.cache[key];
console.log(this.cache);
this.cache[key] = temp;
return temp;
} else {
return -1;
}
};
LRUCache.prototype.put = function(key, value) {
if(this.length < this.cap && this.cache[key] == undefined) {
this.cache[key] = value;
this.length++;
} else if(this.length == this.cap && this.cache[key] == undefined) {
var arr = Object.keys(this.cache);
delete this.cache[arr[0]];
this.cache[key] = value;
}
console.log(this.cache);
};
1.利用collections库中已有的记住数据添加顺序的字典子类OrderedDic()来储存
2.每操作一次键值对,就pop一次再录入一次
3.函数popitem(last=)当参数last=True时是栈LIFO,last=False时是队列FIFO,此处‘最近最少使用’是队列FIFO特征,则用last=False
import collections
class LRUCache:
def __init__(self, capacity: int):
self.cache = collections.OrderedDict()
self.size = capacity
def get(self, key: int) -> int:
if key in self.cache:
res = self.cache.pop(key)
self.cache[key] = res
else:
res = -1
return res
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.cache.pop(key)
self.cache[key] = value
elif len(self.cache) == self.size:
self.cache.popitem(last=False)
self.cache[key] = value
T(n) = O(1)
S(n) = O(n),n为capacity
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.map = new Map();
this.capacity = capacity;
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if(this.map.has(key)){
let value = this.map.get(key)
this.map.delete(key)
this.map.set(key, value)
return value
}
return -1
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if (this.map.has(key)) {
this.map.delete(key)
}
this.map.set(key, value)
if(this.map.size > this.capacity){
this.map.delete(this.map.keys().next().value)
}
};
复杂度分析 时间复杂度:O(1) 空间复杂度:O(N)
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.map = new Map();
this.size = capacity;
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
let val = this.map.get(key)
if (val !== undefined) {
this.map.delete(key)
this.map.set(key, val);
return val
}
return -1;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if (this.map.has(key)) {
this.map.delete(key);
} else if (this.map.size >= this.size) {
const k = this.map.keys().next().value;
this.map.delete(k);
}
this.map.set(key, value);
};
双向链表+hashmap
class DoubleLinkedListNode {
constructor(key,value) {
this.key = key;
this.value = value;
this.prev = null;
this.next = null;
}
}
class LRUCache {
constructor(capacity){
this.capacity = capacity;
this.hashmap = {}
this.useSize = 0;
this.dummyHead= new DoubleLinkedListNode(null,null);
this.dummyTail= new DoubleLinkedListNode(null,null);
this.dummyHead.next = this.dummyTail;
this.dummyTail.prev = this.dummyHead;
}
_isFull(){
return this.useSize === this.capacity;
}
_removeNode(node){
node.prev.next = node.next;
node.next.prev = node.prev;
node.prev = null;
node.next = null;
return node;
}
_addToHead(node){
const head = this.dummyHead.next;
node.next = head;
node.prev = this.dummyHead;
this.dummyHead.next = node;
head.prev = node;
}
get(key){
if(this.hashmap[key]){
const node = this.hashmap[key];
const removeNode = this._removeNode(node);
this._addToHead(removeNode);
return node.value;
}else{
return -1;
}
}
put(key,val){
if(this.hashmap[key]){
const node = this.hashmap[key];
node.value = val;
this._addToHead(this._removeNode(node))
}else{
if(this._isFull()){
// 先获取最后一个
const node = this.dummyTail.prev;
this._removeNode(node);
delete this.hashmap[node.key];
this.useSize--;
}
const node = new DoubleLinkedListNode(key,val);
this.hashmap[key] = node;
this._addToHead(node)
this.useSize++
}
}
}
class LRUCache {
constructor (opacity) {
this.size = opacity
this._storage = new Map()
}
get (key) {
if (this._storage.has(key)) {
const value = this._storage.get(key)
this._storage.delete(key)
this._storage.set(key, value)
return value
} else {
return -1
}
}
put (key, value) {
this._storage.delete(key)
this._storage.set(key, value)
if (this._storage.size > this.size) {
this._storage.delete(this._storage.keys().next().value)
}
}
}
class ListNode:
def __init__(self, key, val):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache: def init(self, capacity: int): self.capacity = capacity self.hashmap = {} self.head = ListNode(0, 0) self.tail = ListNode(0, 0) self.head.next = self.tail self.tail.prev = self.head
def insert(self, node: ListNode):
prev = self.tail.prev
prev.next = node
node.prev = prev
node.next = self.tail
self.tail.prev = node
def remove(self, node: ListNode):
prev = node.prev
next = node.next
prev.next = next
next.prev = prev
def get(self, key: int) -> int:
if key in self.hashmap:
self.remove(self.hashmap[key])
self.insert(self.hashmap[key])
return self.hashmap[key].val
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.hashmap:
self.remove(self.hashmap[key])
self.hashmap[key] = ListNode(key, value)
self.insert(self.hashmap[key])
if len(self.hashmap) > self.capacity:
lru = self.head.next
self.remove(lru)
del self.hashmap[lru.key]
Time: O(1)
Space: O(n)
class LRUCache(collections.OrderedDict):
def __init__(self, capacity: int):
super().__init__()
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self:
return -1
self.move_to_end(key)
return self[key]
def put(self, key: int, value: int) -> None:
if key in self:
self.move_to_end(key)
self[key] = value
if len(self) > self.capacity:
self.popitem(last=False)
使用 map 存储节点信息,使用链表存储节点访问情况
import { ListNode } from "@utils/list-node"
export class LRUCache {
private dataNodeMap = new Map<number, ListNode<{key: number, val: number}>>()
private outdateLink = new ListNode<{key: number, val: number}>()
constructor(private readonly capacity: number) {}
get(key: number): number {
if (!this.dataNodeMap.has(key)) {
return -1
}
const node = this.dataNodeMap.get(key)!
this.updateNode(node)
return node.val.val
}
put(key: number, value: number): void {
// 更新逻辑
if (this.dataNodeMap.has(key)) {
const node = this.dataNodeMap.get(key)!
node.val.val = value
this.updateNode(node)
} else { // 插入逻辑
const node = new ListNode<{key: number, val: number}>({key, val: value})
this.dataNodeMap.set(key, node)
node.next = this.outdateLink.next
this.outdateLink.next = node
this.removeTailNode()
}
}
// 删除过期的尾节点
private removeTailNode() {
let index = 0
let cur = this.outdateLink
while (cur) {
if (index > this.capacity) {
this.dataNodeMap.delete(cur.val.key)
cur.next = null
}
cur = cur.next!
index++
}
}
private updateNode(node: ListNode<{key: number, val: number}>) {
let pre: ListNode<{key: number, val: number}> = this.outdateLink
let cur: ListNode<{key: number, val: number}> = this.outdateLink.next!
while (cur !== node) {
pre = cur
cur = cur.next!
}
pre.next = cur.next
cur.next = this.outdateLink.next
this.outdateLink.next = cur
}
}
目前是使用单向链表实现的,导致 get put 复杂度都不是 O(1),使用双向链表即可进行优化
146. LRU 缓存机制
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/lru-cache/
前置知识
暂无
题目描述