- Posted by 微博@Yangsc_o
- 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
本题是leetcode,地址:146. LRU缓存机制
题目
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得关键字 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得关键字 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
解题思路
LRU 算法实际上是让你设计数据结构:首先要接收一个 capacity 参数作为缓存的最大容量,然后实现两个 API,一个是 put(key, val) 方法存入键值对,另一个是 get(key) 方法获取 key 对应的 val,如果 key 不存在则返回 -1。
注意哦,get 和 put 方法必须都是 O(1)O(1) 的时间复杂度,在双向链表的实现中,使用一个伪头部(dummy head)和伪尾部(dummy tail)标记界限,这样在添加节点时添加到头节点,删除时,删除尾节点的数据。
初始化
put
get
code
class LRUCache {
class MyNode {
int key;
int value;
MyNode prev;
MyNode next;
public MyNode() {
}
public MyNode(int _key, int _value) {
key = _key;
value = _value;
}
}
private int capacity;
private int size;
private Map<Integer, MyNode> cache = new HashMap<>();
private MyNode head, tail;
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
this.head = new MyNode();
this.tail = new MyNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
MyNode node = cache.get(key);
if (node == null) {
return -1;
} else {
// 更换到头节点
moveToHead(node);
return node.value;
}
}
private void moveToHead(MyNode node) {
removeNode(node);
addToHead(node);
}
public void put(int key, int value) {
MyNode node = cache.get(key);
if (node == null) {
node = new MyNode(key, value);
addToHead(node);
size++;
if (size > capacity) {
MyNode tail = removeTail();
cache.remove(tail.key);
size--;
}
cache.put(key,node);
} else {
node.value = value;
moveToHead(node);
}
}
private void addToHead(MyNode node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private MyNode removeTail() {
MyNode node = tail.prev;
removeNode(node);
return node;
}
private void removeNode(MyNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
}
/**
* 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);
*/