原题网址:https://leetcode.com/problems/lru-cache/
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.
方法:使用双向链表保存key的访问顺序,使用哈希映射来快速定位到链表的节点,以便进行移动操作。
public class LRUCache { private LinkNode head; private LinkNode tail; private Map<Integer, LinkNode> map; private int capacity; public LRUCache(int capacity) { this.capacity = capacity; this.map = new HashMap<>(capacity); } public int get(int key) { // System.out.println("Getting " + key); LinkNode node = map.get(key); if (node == null) return -1; // System.out.println("Got Node(" + node.value + ")"); if (node == tail) return node.value; if (node == head) { this.head = node.next; node.next.previous = null; node.next = null; this.tail.next = node; node.previous = this.tail; this.tail = node; } else { node.next.previous = node.previous; node.previous.next = node.next; node.next = null; node.previous = this.tail; this.tail.next = node; this.tail = node; } return node.value; } public void set(int key, int value) { // System.out.println("Setting key " + key + "= " + value); if (this.capacity <= 0) return; LinkNode node = map.get(key); if (node != null) { node.value = value; if (node == tail) return; if (node == head) { this.head = node.next; node.next.previous = null; node.next = null; this.tail.next = node; node.previous = this.tail; this.tail = node; } else { node.next.previous = node.previous; node.previous.next = node.next; node.next = null; node.previous = this.tail; this.tail.next = node; this.tail = node; } } else if (this.map.size() < this.capacity) { node = new LinkNode(key, value); map.put(key, node); if (head == null) { head = node; tail = node; } else { this.tail.next = node; node.previous = this.tail; this.tail = node; } } else { // System.out.println("Setting key " + key + "= " + value + ", replacing"); node = new LinkNode(key, value); map.remove(this.head.key); map.put(key, node); if (this.capacity == 1) { // System.out.println("Setting key " + key + "= " + value + ", capacity=1"); this.head = node; this.tail = node; } else { this.head.next.previous = null; this.head = this.head.next; this.tail.next = node; node.previous = this.tail; this.tail = node; } } } } class LinkNode { int key; int value; LinkNode previous, next; public LinkNode(int key, int value) { this.key = key; this.value = value; } }
封装简化:
public class LRUCache { private Cache head = new Cache(0, 0); private Cache tail = new Cache(0, 0); { head.insert(tail); } private Map<Integer, Cache> map = new HashMap<>(); private int capacity; public LRUCache(int capacity) { this.capacity = capacity; } public int get(int key) { Cache cache = map.get(key); if (cache == null) return -1; cache.remove(); cache.insert(tail); return cache.value; } public void set(int key, int value) { if (capacity <= 0) return; Cache cache = map.get(key); if (cache == null) { cache = new Cache(key, value); cache.insert(tail); if (map.size() >= capacity) { map.remove(head.right.key); head.right.remove(); } map.put(key, cache); } else { cache.value = value; cache.remove(); cache.insert(tail); } } } class Cache { int key, value; Cache left, right; Cache(int key, int value) { this.key = key; this.value = value; } void remove() { if (this.left != null) this.left.right = this.right; if (this.right != null) this.right.left = this.left; this.left = null; this.right = null; } void insert(Cache before) { this.left = before.left; if (this.left != null) this.left.right = this; before.left = this; this.right = before; } }