题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。
它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1); cache.put(2, 2); cache.get(1); // 返回 1 cache.put(3, 3); // 该操作会使得密钥 2 作废 cache.get(2); // 返回 -1 (未找到) cache.put(4, 4); // 该操作会使得密钥 1 作废 cache.get(1); // 返回 -1 (未找到) cache.get(3); // 返回 3 cache.get(4); // 返回 4
|
思路
使用hashmap和自定义一个双向链表,hashmap主要用于存储数据,而双向链表用于设置最久最新使用
双向链表的头部和尾部没有数据,只是用作一个标志位
创建一个hashmap,key为值,value为node,创建头尾指针,size和capacity
先进行put方法,先判断缓存中是否有这个数据
- 如果没有,缓存中放入,创建一个节点放在头部
- 如果有,缓存中数据覆盖,节点移动到头部
get操作,缓存中没有直接返回-1,缓存中有,把value放到头部
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static void main(String[] args) { LRUCache2 cache = new LRUCache2(2 /* 缓存容量 */);
cache.put(1, 1); cache.put(2, 2); // 返回 1 System.out.println(cache.get(1)); // 该操作会使得密钥 2 作废 cache.put(3, 3); // 返回 -1 (未找到) System.out.println(cache.get(2)); // 该操作会使得密钥 1 作废 cache.put(4, 4); // 返回 -1 (未找到) System.out.println(cache.get(1)); // 返回 3 System.out.println(cache.get(3)); // 返回 4 System.out.println(cache.get(4));
}
|
借用LinkedHashMap
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
| private static class LRUCache extends LinkedHashMap<Integer, Integer> { private int capacity;
public LRUCache(int capacity) { super(capacity, 0.75F, true); this.capacity = capacity; }
public int get(int key) { return super.getOrDefault(key, -1); }
public void put(int key, int value) { super.put(key, value); }
@Override protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) { return size() > capacity; } }
|
自己实现
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
| private static class LRUCache2 { private final static class DLinkedNode { int key; int value; DLinkedNode prev; DLinkedNode next;
private DLinkedNode(int key, int value) { this.key = key; this.value = value; }
public DLinkedNode() {
} }
private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>(); private int size; private int capacity; private DLinkedNode head, tail;
public LRUCache2(int capacity) { this.size = 0; this.capacity = capacity; head = new DLinkedNode(); tail = new DLinkedNode(); head.next = tail; tail.prev = head; }
public int get(int key) { DLinkedNode node = cache.get(key); if (node == null) { return -1; } moveToHead(node); return node.value; }
public void put(int key, int value) { DLinkedNode node = cache.get(key); if (node == null) { DLinkedNode newNode = new DLinkedNode(key, value); cache.put(key, newNode); addToHead(newNode); size++; if (size > capacity) { DLinkedNode tail = removeTail(); cache.remove(tail.key); size--; } } else { node.value = value; moveToHead(node); }
}
private void addToHead(DLinkedNode node) { node.prev = head; node.next = head.next; head.next.prev = node; head.next = node; }
private void removeNode(DLinkedNode node) { node.prev.next = node.next; node.next.prev = node.prev; }
private void moveToHead(DLinkedNode node) { removeNode(node); addToHead(node); }
private DLinkedNode removeTail() { DLinkedNode res = tail.prev; removeNode(res); return res; }
}
|