NO.146 LRU缓存机制 中等
思路一:双向链表+HashMap 双向链表确保插入和删除快是个 O(1) ,但是查找时链表的硬伤.
需要用一个 HashMap 去弥补链表查找上的问题,Map 的 key 存放节点的 key 、Map 的 value 存放对应的节点,形成 Map[key,node]->Node[key,value]
这样的映射,从而确保了通过 key 查找节点时的速度问题。
先实现一个双向链表,要有插入/删除操作:
1 2 3 4 5 6 7 8 9 10 11
| public class Node { int key, value; Node next, pre;
public Node(int key, int value) { this.key = key; this.value = 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
| public class DoubleLinkedList { Node head, tail; int size;
public DoubleLinkedList() { head = new Node(-1, -1); tail = new Node(-1, -1); head.next = tail; tail.next = head; size = 0; }
public boolean addFirst(Node node) { node.next = head.next; node.pre = head; head.next.pre = node; head.next = node; size++; return true; }
public boolean remove(Node node) { node.pre.next = node.next; node.next.pre = node.pre; size--; return true; }
public Node removeLast() { if (head.next == tail) return null; Node last = tail.pre; remove(last); return last; }
public int size() { return size; } }
|
接下来就可以开始实现 LRUCache 了,最近访问过的节点放到链表头部,缓存已满时发生页面替换将表尾的节点删除,节点被访问之后放到表头:
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
| public class LRUCache { HashMap<Integer, Node> map; DoubleLinkedList cache; int capacity;
public LRUCache(int capacity) { map = new HashMap<>(); cache = new DoubleLinkedList(); this.capacity = capacity; }
public void put(int key, int value) { Node node = new Node(key, value); if (map.containsKey(key)) { cache.remove(map.get(key)); } else if (cache.size == capacity) { Node last = cache.removeLast(); map.remove(last.key); } cache.addFirst(node); map.put(key, node); }
public int get(int key) { if (!map.containsKey(key)) return -1; int value = map.get(key).value; put(key, value); return value; }
}
|
get/put 时间复杂度:O(1)
本人菜鸟,有错误请告知,感激不尽!
更多题解和源码:github