LeetCode刷题笔记 —— 146 LRU的实现 题目解析: 设计一个LRU缓存,规定好最大容量,设计get/put接口,当即将超出容量的时候,要把最久未使用的缓存删除
最久未使用:最久没有进行 get/put操作
要求get/put均为o(1)复杂度
o(1)的key value,必然是哈希表,可是应该怎么获取 最久未使用 这一个信息?
第一思路:把 最久未获取 当成一个属性来维护
最久未使用 这一信息的获取过程,是伴随着 put 操作发生的,因此,put想要是O(1),获取最久未使用也必须是O(1)
换句话说,我们想要这个信息的获取既能和key的获取一样便捷,又能把他和key联系起来
然而,哈希表也仅有key能在O(1)时间内获取,getvalue则是通过遍历哈希key获得的,时间复杂度是O(n)
同样的道理,使用 栈 Stack 来维护这个信息,在移除头节点的时候,remove(0)操作也是需要O(n)的时间
**第二思路:1. 利用某种数据结构的特性,把时间信息隐含到数据结构里 **
**2.必须满足通过key查找到它的过程不是O(n)遍历,而是直接得到 **
因此我们使用 双向链表 作为数据结构,因为双向链表可以在O(1)的复杂度内,完成节点的拆除,移位等,保证了 操作的过程不用去遍历
但是,还有一个很大的问题,就是如果我们的哈希表是 key value,在双向链表中存的信息是key,那我们可以很轻松的通过节点拿到key,但反过来就不行了,也就是没有满足第二条,必须满足通过key查找到它的过程不是O(n)遍历
既然我们已经自定义节点了,节点能存什么,我们是完全能控制的,所以,为啥一定要让链表作为map的小弟,去只给他存key呢?
因此,我们可以做以下改进:
让节点存 key ,value
不让map存value了,我们缓存的主体是链表 ,map只用来进行唯一性判断和大小统计,所以,map的value字段直接存节点
代码实现如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 class LRUCache { HashMap <Integer,Node> cacheMap; Node head; Node tail; int capacity; public LRUCache (int capacity) { head = new Node (); tail = new Node (); head.setNext(tail); tail.setPre(head); this .capacity = capacity; cacheMap = new HashMap (); } public int get (int key) { if (cacheMap.containsKey(key)){ Node tempNode = cacheMap.get(key); tempNode.getPre().setNext(tempNode.getNext()); tempNode.getNext().setPre(tempNode.getPre()); tempNode.setNext(tail); tempNode.setPre(tail.getPre()); tempNode.getPre().setNext(tempNode); tail.setPre(tempNode); return tempNode.getValue(); } return -1 ; } public void put (int key, int value) { Boolean keyExists = cacheMap.containsKey(key); if (!keyExists){ if (cacheMap.size()==capacity){ Node delNode = head.getNext(); head.setNext(delNode.getNext()); delNode.getNext().setPre(head); int delKey = delNode.getKey(); delNode = null ; cacheMap.remove(delKey); } Node newNode = new Node (); newNode.setValue(value); newNode.setKey(key); newNode.setPre(tail.getPre()); newNode.setNext(tail); newNode.getPre().setNext(newNode); tail.setPre(newNode); cacheMap.put(key,newNode); }else { Node changeNode = cacheMap.get(key); changeNode.getPre().setNext(changeNode.getNext()); changeNode.getNext().setPre(changeNode.getPre()); changeNode.setNext(tail); changeNode.setPre(tail.getPre()); changeNode.setValue(value); tail.getPre().setNext(changeNode); tail.setPre(changeNode); } } } public class Node { private Node preNode; private Node nextNode; private int value; private int key; public Node getPre () { return preNode; } public Node getNext () { return nextNode; } public void setPre (Node preNode) { this .preNode = preNode; } public void setNext (Node nextNode) { this .nextNode = nextNode; } public int getValue () { return value; } public void setValue (int value) { this .value = value; } public int getKey () { return key; } public void setKey (int key) { this .key = key; } }