思路
这题的关键是同时满足两个要求:
- O(1) 查找 :所以要用
HashMap。 - 维护最近使用顺序 :所以要用 双向链表。
只用 HashMap 可以 O(1) 找到 key,但不知道哪个是"最近最少使用"的;
只用链表可以维护顺序,但查找是 O(n)。
所以要把两者结合起来。
数据结构设计
维护一个 双向链表,链表头部表示最近使用的,尾部表示最久未使用的。
同时维护一个 HashMap<Integer, Node>,用来 O(1) 找到某个 key 对应的节点。
-
get(key):- 如果 key 不存在,返回
-1。 - 如果存在,把对应节点移到链表头部,表示最近使用过,然后返回它的值。
- 如果 key 不存在,返回
-
put(key, value):- 如果 key 已存在,更新值,并把节点移到链表头部。
- 如果 key 不存在:
- 新建节点,插入链表头部,并放入 map。
- 如果超过容量,就删除链表尾部节点,同时从 map 中移除。
class LRUCache {
class Node{
int key;
int value;
Node prev;
Node next;
public Node(int key,int value ){
this.key=key;
this.value=value;
}
}
private final int capacity;
private final Map<Integer,Node> map;
private final Node head;
private final Node tail;
public LRUCache(int capacity) {
this.capacity=capacity;
this.map=new HashMap<>();
head=new Node(0,0);
tail=new Node(0,0);
head.next=tail;
tail.prev=head;
}
public int get(int key) {
if(!map.containsKey(key))
return -1;
Node node=map.get(key);
movetohead(node);
return node.value;
}
public void put(int key, int value) {
if(map.containsKey(key)){
Node node=map.get(key);
node.value=value;
movetohead(node);
return;
}
Node node=new Node(key,value);
map.put(key,node);
addtohead(node);
if(map.size()>capacity){
Node lastnode=tail.prev;
removetail();
map.remove(lastnode.key);
return;
}
}
private void addtohead(Node node){
head.next.prev=node;
node.prev=head;
node.next=head.next;
head.next=node;
}
private void removenode(Node node){
node.prev.next=node.next;
node.next.prev=node.prev;
}
private void movetohead(Node node){
removenode(node);
addtohead(node);
}
private Node removetail(){
Node lastnode=tail.prev;
removenode(lastnode);
return lastnode;
}
}
/**
* 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);
*/