LeetCode Top 100 Liked Questions 146. LRU Cache (Java版; Medium)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode Top 100 Liked Questions 146. LRU Cache (Java版; Medium)相关的知识,希望对你有一定的参考价值。
welcome to my blog
LeetCode Top 100 Liked Questions 146. LRU Cache (Java版; Medium)
题目描述
Design and implement a data structure for Least Recently Used (LRU,最近最少使用) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate
the least recently used item before inserting a new item.
The cache is initialized with a positive capacity.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // returns 1
cache.put(3, 3); // evicts key 2
cache.get(2); // returns -1 (not found)
cache.put(4, 4); // evicts key 1
cache.get(1); // returns -1 (not found)
cache.get(3); // returns 3
cache.get(4); // returns 4
class LRUCache
DoubleLinkedList dll;
int capacity;
HashMap<Integer, Node> map;
public LRUCache(int capacity)
dll = new DoubleLinkedList();
this.capacity = capacity;
map = new HashMap<>();
public int get(int key)
if(!map.containsKey(key))
return -1;
dll.moveToTail(map.get(key));
return map.get(key).val;
public void put(int key, int value)
if(map.containsKey(key))
map.get(key).val = value;
dll.moveToTail(map.get(key));
return;
if(map.size()==capacity)
Node node = dll.removeHead();
map.remove(node.key);
Node node = new Node(key, value);
dll.addToTail(node);
map.put(key, node);
private class Node
int key;
int val;
Node pre;
Node next;
Node(int key, int val)
this.key = key;
this.val = val;
//双向链表; 提供三个方法:(1)将元素添加到队尾 (2)将元素移动到队尾 (3)删除队首元素
private class DoubleLinkedList
Node head;
Node tail;
private void addToTail(Node node)
if(head==null)
head = node;
tail = node;
else
tail.next = node;
node.pre = tail;
tail = node;
private void moveToTail(Node node)
//如果链表中只有一个元素
if(node==tail)
return;
//如果链表中至少有两个元素
if(node==head)
head = head.next;
head.pre = null;
node.next = null;
//
tail.next = node;
node.pre = tail;
//
tail = node;
else
Node left = node.pre;
left.next = node.next;
node.next.pre = left;
//
tail.next = node;
node.pre = tail;
//
tail = node;
private Node removeHead()
Node node=head;
if(head==tail)
head=null;
tail=null;
else
head = head.next;
head.pre = null;
return node;
第一次做; 这道题让我体会到基础数据结构太重要了, 复杂的数据结构是由基础数据结构构成的; 核心: 双向链表+哈希表, 双向链表的头结点是最不常用的数据, 双向链表的尾结点是最常用的数据; 要自定义节点类, 链表类, LRUCache类; 其中, 链表类需要实现三个功能:1)增加节点, 2)删除头结点, 3)将某个节点移动到链表结尾(有细节); LRUCache类需要实现三个功能:1)set, 2)get, 3)缓存满了之后删除最不常用的节点; 定义节点类和链表类的时候不妨使用泛型, 方便扩展到其它数据类型上
/*
双向链表+哈希表
考查的是:根据具体功能设计相应的数据结构的能力; 所以基础的数据结构太重要了! 务必夯实基础
*/
import java.util.HashMap;
//定义双向节点类; 此处为了加深理解, 使用泛型
class Node<V>
public V value;
public Node<V> last;
public Node<V> next;
public Node(V value)
this.value = value;
//定义双向链表类; 需要实现三个功能:1)添加节点 2)将节点挪到最后 3)删除头节点
class DoubleLinkedList<V>
private Node<V> head;
private Node<V> tail;
public DoubleLinkedList()
this.head = null;
this.tail = null;
//1)添加节点
public void addNode(Node<V> newNode)
//input check
if(newNode == null)
return;
//链表为空
if(this.head==null)
this.head = newNode;
this.tail = newNode;
//链表不为为空; 将新节点添加到队列末尾
else
this.tail.next = newNode;
newNode.last = this.tail;
this.tail = newNode;
//2)将节点挪到最后
public void moveNodeToTail(Node<V> node)
//如果node本来就在末尾, 就不用调整了; 这里包含两个情况:1)链表只有一个节点, 不用调整 2)链表有多个节点, 但是node在末尾, 不用调整
if(node == this.tail)
return;
//如果node是头结点; 先改变头结点, 之后再将node挪到最后
if(this.head == node)
this.head = node.next;
this.head.last = null;
//如果node不是头结点; 先将node左右两侧的节点连接, 之后再将node挪到最后
else
node.last.next = node.next;
node.next.last = node.last;
//将node挪到最后; 主要node的last和next指针都要变动
this.tail.next = node;
node.last = this.tail;
node.next = null;
this.tail = node;
//3)删除头节点
public Node<V> removeHead()
//如果链表为空
if(this.head==null)
return null;
Node<V> curr = this.head;
//如果链表只有一个节点; 删除头结点后, head和tail指针变为null
if(this.head == this.tail)
this.head = null;
this.tail = null;
//如果链表有多个节点; 删除头结点后, head指针变了, tial指针可能改变(如果有两个节点,tail.last会变; 如果有两个以上的节点, tail不会变)
else
//删除头节点需要改变头结点的last和next指针; 这一点和挪动节点很像, 都是需要改变两个指针
this.head = this.head.next;
this.head.last = null;
curr.next = null;
return curr;
class LRUCache
private HashMap<Integer, Node<Integer>> keyNodeMap;
private HashMap<Node<Integer>, Integer> nodeKeyMap;
//双向链表
private DoubleLinkedList<Integer> nodeList;
private int capacity;
public LRUCache(int capacity)
//input check
if(capacity < 1)
throw new RuntimeException("capacity is not valid!!!!!!!!!");
this.capacity = capacity;
this.keyNodeMap = new HashMap<Integer, Node<Integer>>();
this.nodeKeyMap = new HashMap<Node<Integer>, Integer>();
this.nodeList = new DoubleLinkedList<Integer>();
public int get(int key)
//链表不包含key, 返回-1
if(!keyNodeMap.containsKey(key))
return -1;
//链表中包含key, 返回对应的value
else
Node<Integer> res = keyNodeMap.get(key);
//将该节点更新成: 最常使用的, 也就是把该节点挪到链表末尾
nodeList.moveNodeToTail(res);
return res.value;
public void put(int key, int value)
//如果链表中包含key
if(keyNodeMap.containsKey(key))
Node curr = keyNodeMap.get(key);
curr.value = value;
//将该节点更新成: 最常使用的
nodeList.moveNodeToTail(curr);
//如果链表中不包含key; 需要创建一个新的节点
else
//先检查缓存是否已满; 满的话, 需要删除头结点
if(keyNodeMap.size() == this.capacity)
removeMostUnusedCache();
//确保缓存有空间后再加入新的记录
Node<Integer> node = new Node<>(value);
//更新哈希表中的记录
this.keyNodeMap.put(key, node);
this.nodeKeyMap.put(node, key);
//把节点添加到链表中
nodeList.addNode(node);
public void removeMostUnusedCache()
Node<Integer> curr = this.nodeList.removeHead();
//更新哈希表
int key = nodeKeyMap.get(curr);
this.keyNodeMap.remove(key);
keyNodeMap.remove(curr);
/**
* 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);
*/
以上是关于LeetCode Top 100 Liked Questions 146. LRU Cache (Java版; Medium)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)
LeetCode Top 100 Liked Questions 10.Regular Expression Matching (Java版; Hard)
LeetCode Top 100 Liked Questions 142. Linked List Cycle II (Java版; Medium)
LeetCode Top 100 Liked Questions 98. Validate Binary Search Tree (Java版; Medium)
LeetCode Top 100 Liked Questions 124. Binary Tree Maximum Path Sum (Java版; Hard)