LRU Cache
Problem Description
Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
Implement the LRUCache class:
LRUCache(int capacity)Initialize the LRU cache with positive size capacity.int get(int key)Return the value of thekeyif the key exists, otherwise return-1.void put(int key, int value)Update the value of thekeyif thekeyexists. Otherwise, add thekey-valuepair to the cache. If the number of keys exceeds thecapacityfrom this operation, evict the least recently used key.
The functions get and put must each run in $O(1)$ average time complexity.
Approach
Hash Map + Doubly Linked List
- Hash Map: Stores
key->Nodemapping for $O(1)$ access. - Doubly Linked List: Maintains the order of elements.
- Head: Most recently used.
- Tail: Least recently used.
- Operations:
- Get: Look up node in map. Move node to head. Return value.
- Put:
- If key exists: Update value, move to head.
- If key new: Create node, add to head, add to map.
- If capacity full: Remove tail node, remove from map.
Code Snippet (TypeScript)
class Node {
key: number;
val: number;
prev: Node | null = null;
next: Node | null = null;
constructor(key: number, val: number) {
this.key = key;
this.val = val;
}
}
class LRUCache {
private capacity: number;
private cache: Map<number, Node>;
private head: Node;
private tail: Node;
constructor(capacity: number) {
this.capacity = capacity;
this.cache = new Map();
// Dummy head and tail
this.head = new Node(0, 0);
this.tail = new Node(0, 0);
this.head.next = this.tail;
this.tail.prev = this.head;
}
private remove(node: Node): void {
const prev = node.prev!;
const next = node.next!;
prev.next = next;
next.prev = prev;
}
private insert(node: Node): void {
const prev = this.head;
const next = this.head.next!;
prev.next = node;
next.prev = node;
node.prev = prev;
node.next = next;
}
get(key: number): number {
if (this.cache.has(key)) {
const node = this.cache.get(key)!;
this.remove(node);
this.insert(node);
return node.val;
}
return -1;
}
put(key: number, value: number): void {
if (this.cache.has(key)) {
this.remove(this.cache.get(key)!);
}
const newNode = new Node(key, value);
this.cache.set(key, newNode);
this.insert(newNode);
if (this.cache.size > this.capacity) {
const lru = this.tail.prev!;
this.remove(lru);
this.cache.delete(lru.key);
}
}
}