重点
1.构造链表的Node类,需要有值key、value、节点prev、next5
2.链表要有head伪头节点和tail伪尾节点
3.缓存用hashmap<integer,node>
4.size记录数量
5.为了避免重复代码,除了get、put外,我们还有以下方法:delete删除节点、deleteTail删除尾节点、addToHead加到头节点、removeToHead移到头节点。
题目
https://leetcode-cn.com/problems/lru-cache/
代码
class LRUCache {
class DLinkedNode{
int key;
int value;
DLinkedNode prev;
DLinkedNode 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;
private int capacity;
private DLinkedNode head,tail;
public LRUCache(int capacity) {
this.size=0;
this.capacity=capacity;
//使用伪头部和伪尾部节点
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;
}
//如果key存在,先通过哈希表定位,再移到头部
moveToHead(node);
return node.value;
}
public void put(int key, int value) {
DLinkedNode node=cache.get(key);
if(node==null){
//如果key不存在,创建一个新的节点
DLinkedNode newNode=new DLinkedNode(key,value);
//添加进哈希表
cache.put(key,newNode);
//添加至双向链表的头部
addToHead(newNode);
//计数+1
++size;
if(size>capacity){
//如果超出容量,删除双向链表的尾部节点
DLinkedNode tail=removeTail();
//删除哈希表中对应的项
cache.remove(tail.key);
--size;//计数-1
}
}
else{
//如果key存在.修改value
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;
}
}
/**
* 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);
*/
class LRUCache {
class Node{
int key;
int val;
Node prev;
Node next;
Node(){
}
Node(int key,int val){
this.key=key;
this.val=val;
}
}
HashMap<Integer,Node> map;
Node head,tail;
int capacity;
int size;
public LRUCache(int capacity) {
map=new HashMap<>();
head=new Node();
tail=new Node();
head.next=tail;
tail.prev=head;
this.capacity=capacity;
this.size=0;
}
public int get(int key) {
if(map.containsKey(key)){
Node node=map.get(key);
moveToHead(node);
return node.val;
}
return -1;
}
public void put(int key, int value) {
int val=get(key);
if(val==-1){//不存在
size++;
Node node=new Node(key,value);
addToHead(node);
map.put(key,node);
//空间不够
if(size>capacity){
Node no=deleteTail();
map.remove(no.key);//从缓存中删除
size--;
}
}
else{//存在
Node node=map.get(key);
node.val=value;
map.put(key,node);
moveToHead(node);
}
}
//删除节点
public void delete(Node node){
node.prev.next=node.next;
node.next.prev=node.prev;
}
//删除尾部
public Node deleteTail(){
Node res=tail.prev;
delete(res);
return res;
}
//加到头部
public void addToHead(Node node){
node.next=head.next;
node.next.prev=node;
head.next=node;
node.prev=head;
}
//移到头部
public void moveToHead(Node node){
delete(node);
addToHead(node);
}
}
复杂度
时间复杂度:对于 put 和 get 都是O(1)。
空间复杂度:O(capacity),因为哈希表和双向链表最多存储capacity+1 个元素。