21.03.14 LeetCode146. LRU 缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]
解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
1 class LRUCache {
2 //先自己实现双向链表,包括方法add2head/removeNode/move2head/removeTail
3 class DoubleLinkedNode
4 {
5 int key;
6 int value;
7 DoubleLinkedNode pre;
8 DoubleLinkedNode next;
9 public DoubleLinkedNode(){}
10 public DoubleLinkedNode(int key,int value){this.key = key;this.value = value;}
11 }
12 //使用哈希表存储key对应的链表节点,节点内存放value值
13 private Map<Integer,DoubleLinkedNode> cache;
14 private int size;
15 private int capacity;
16 private DoubleLinkedNode head,tail;
17 public LRUCache(int capacity) {
18 this.size = 0;
19 this.capacity = capacity;
20 cache = new HashMap<Integer,DoubleLinkedNode>();
21 //伪头部和伪尾部
22 head = new DoubleLinkedNode();
23 tail = new DoubleLinkedNode();
24 head.next = tail;
25 tail.pre = head;
26 }
27
28 public int get(int key) {
29 //查找key有无位于双向链表中,有则返回关键字的值
30 DoubleLinkedNode node = cache.get(key);
31 if(node==null)
32 return -1;
33 else{
34 move2head(node);
35 return node.value;
36 }
37 }
38
39 public void put(int key, int value) {
40 DoubleLinkedNode tep = cache.get(key);
41 if(tep == null)
42 {
43 //key不存在
44 //新建节点
45 DoubleLinkedNode node = new DoubleLinkedNode(key,value);
46 //当缓存容量达到上限
47 if(size==capacity)
48 {
49 //删除尾结点
50 cache.remove(removeTail().key);
51 size--;
52 }
53 //添加进哈希表
54 cache.put(key,node);
55 //添加进链表头部
56 add2head(node);size++;
57
58 }
59 else{
60 //key已存在,变更其数据值
61 tep.value = value;
62 //刚使用过,所以放在链表头部
63 move2head(tep);
64 }
65 }
66 private void add2head(DoubleLinkedNode node)
67 {
68 node.pre = head;
69 node.next = head.next;
70 head.next.pre = node;
71 head.next = node;
72 }
73 private void removeNode(DoubleLinkedNode node)
74 {
75 node.pre.next = node.next;
76 node.next.pre = node.pre;
77 }
78 private void move2head(DoubleLinkedNode node)
79 {
80 //移动当前节点至头结点
81 removeNode(node);
82 add2head(node);
83 }
84 private DoubleLinkedNode removeTail()
85 {
86 DoubleLinkedNode rem = tail.pre;
87 removeNode(rem);
88 return rem;
89 }
90 }