题目:146. LRU 缓存
思路:哈希表+双向链表,时间复杂度0(n)。
get、put时间复杂度必须为0(n),那么就得用空间换时间。双向链表来记录每一个节点node(key-value),哈希表来记录每一个key所对应的节点node。
在get、put时,先判断哈希表mp里是否存储了key,而双向链表是维护每一个节点的访问顺序。
C++版本:
class LRUCache {
// 节点node
typedef struct Node{
int key;
int val;
Node * prev;
Node * next;
Node(int k,int v):key(k),val(v){}
}node;
// 哈希表的最大容量
int capt;
// 双向链表的哨兵节点
node *head;
// 哈希表
unordered_map<int,node *> mp;
public:
// 将双向链表的节点x删除
void deletee(node * x){
x->prev->next=x->next;
x->next->prev=x->prev;
}
// 将节点x插入到双向链表的头节点,也就是哨兵节点head的右边
void insertt(node * x){
x->prev=head;
x->next=head->next;
x->prev->next=x;
x->next->prev=x;
}
// 初始化内置函数
LRUCache(int capacity) {
capt=capacity;
head=new node(0,0);
head->next=head;
head->prev=head;
}
int get(int key) {
if(mp.find(key)==mp.end()) return -1;
deletee(mp[key]);
insertt(mp[key]);
return mp[key]->val;
}
void put(int key, int value) {
// 哈希表存在key
if(mp.find(key)!=mp.end()){
node * tmp=mp[key];
tmp->val=value;
deletee(tmp);
insertt(tmp);
return ;
}
// 哈希表不存在key
mp[key]=new node(key,value);
insertt(mp[key]);
// 哈希表容量大于capacity
if(mp.size()>capt){
// 通过哨兵节点head找到最后一个节点
node * bak=head->prev;
deletee(bak);
mp.erase(bak->key);
delete bak;
}
}
};
/**
* 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);
*/
JAVA版本:
class LRUCache {
class node{
int key;
int val;
node prev,next;
node(int k,int v){
key=k;
val=v;
}
}
int capt;
node head=new node(0,0);
Map<Integer,node> mp=new HashMap<>();
void deletee(node x){
x.prev.next=x.next;
x.next.prev=x.prev;
}
void insertt(node x){
x.prev=head;
x.next=head.next;
x.prev.next=x;
x.next.prev=x;
}
LRUCache(int capacity) {
capt=capacity;
head.next=head;
head.prev=head;
}
int get(int key) {
if(mp.containsKey(key)==false) return -1;
deletee(mp.get(key));
insertt(mp.get(key));
return mp.get(key).val;
}
void put(int key, int value) {
if(mp.containsKey(key)==true){
node tmp=mp.get(key);
tmp.val=value;
deletee(tmp);
insertt(tmp);
return ;
}
mp.put(key,new node(key,value));
insertt(mp.get(key));
if(mp.size()>capt){
node bak=head.prev;
deletee(bak);
mp.remove(bak.key);
}
}
}
/**
* 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);
*/
GO版本:
type node struct{
key,val int
prev,next *node
}
type LRUCache struct {
capacity int
head *node
mp map[int]*node
}
func Constructor(capacity int) LRUCache {
nd:=&node{
key:0,
val:0,
}
nd.prev=nd
nd.next=nd
return LRUCache{
capacity :capacity,
head :nd,
mp :map[int]*node{},
}
}
func (this *LRUCache) deletee(x *node){
x.prev.next=x.next
x.next.prev=x.prev
}
func (this *LRUCache) insertt(x *node){
x.prev=this.head
x.next=this.head.next
x.prev.next=x
x.next.prev=x
}
func (this *LRUCache) getNode(key int) *node{
nd,ok :=this.mp[key]
if !ok {
return nil
}
this.deletee(nd)
this.insertt(nd)
return nd
}
func (this *LRUCache) Get(key int) int {
nd:=this.getNode(key)
if nd==nil {
return -1
}
return nd.val
}
func (this *LRUCache) Put(key int, value int) {
nd:=this.getNode(key)
if nd!=nil {
nd.val=value
return
}
this.mp[key]=&node{
key :key,
val :value,
}
this.insertt(this.mp[key])
if len(this.mp)>this.capacity {
bak:=this.head.prev
this.deletee(bak)
delete(this.mp,bak.key)
}
return
}
/**
* Your LRUCache object will be instantiated and called as such:
* obj := Constructor(capacity);
* param_1 := obj.Get(key);
* obj.Put(key,value);
*/