Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations:
get
and set
.get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.set(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.
Solution: HashMap + Double Linked List
用一个hashmap来维护结点的位置关系,hashmap的key就是资源本身的key,value是资源的结点(包含key和value的信息)。
把node维护成一个双向链表构成的队列,这样子如果我们要访问某一个结点,那么可以通过hash表和key来找到结点,从而取到相应的value。而当我们想要删除或者插入结点时,我们还是通过hash表找到结点,然后通过双向链表和队列的尾结点把自己删除同时插入到队尾。
通过hash表访问结点我们可以认为是O(1)的操作,然后双向链表的插入删除操作也是O(1)的。所以用O(1)时间来完成所有LRU cache的操作。空间上就是对于每一个资源有一个hash表的的项以及一个对应的结点(包含前后指针和资源的<key, value>)。
public class LRUCache { //DoubleLinkedListNode constructor class DoubleLinkedListNode { int val; int key; DoubleLinkedListNode pre; DoubleLinkedListNode next; public DoubleLinkedListNode(int key, int val) { this.key = key; this.val = val; } } private DoubleLinkedListNode first; private DoubleLinkedListNode last; private HashMapmap; //key is the key, value is the node which contains its key&value private int capacity; private int num; public LRUCache(int capacity) { this.capacity = capacity; num = 0; first = null; last = null; map = new HashMap (); } public int get(int key) { DoubleLinkedListNode node = map.get(key); if(node == null) { //key doesn't exist return -1; }else if(node != last) { if(node == first) { first = first.next; }else { node.pre.next = node.next; } node.next.pre = node.pre; last.next = node; node.pre = last; // move node to the last one node.next = null; last = node; } return node.val; } public void set(int key, int value) { DoubleLinkedListNode node = map.get(key); if(node != null) { // if first node exists, asign value to it and move to the last one (相当于删除了第一个node) node.val = value; if(node != last) { if(node == first) { first = first.next; }else { node.pre.next = node.next; } node.next.pre = node.pre; last.next = node; node.pre = last; node.next = null; last = node; } }else { DoubleLinkedListNode newNode = new DoubleLinkedListNode(key, value); if(num >= capacity) { map.remove(first.key); first = first.next; if(first != null) { first.pre = null; }else { last = null; } num--; } if(first == null || last == null) { first = newNode; }else { last.next = newNode; } newNode.pre = last; last = newNode; map.put(key, newNode); // don't forget to add the newNode into map num++; } } }
No comments:
Post a Comment