← Back to All Algorithms

Medium Interview Frequency: ⭐⭐⭐⭐⭐

LRU Cache

Design get and put in O(1), evicting the least recently used key when capacity is exceeded.

DesignLinked ListHash Map

📚 Table of Contents

  1. Problem Statement
  2. Real-World Analogy
  3. Key Insights
  4. Solution Approach
  5. Step-by-Step Walkthrough
  6. Complexity Analysis
  7. Edge Cases
  8. Test Cases
  9. Interview Tips
  10. Key Takeaways

📋 Problem Statement

Implement:

If cache size exceeds capacity, evict the least recently used key.

🎯 Real-World Analogy

Desk With Active Files

You keep a small stack of active files. Touching a file moves it to top. Adding a new file when desk is full removes the oldest untouched file.

💡 Key Insights

💻 Solution Approach

Time: O(1) per get/put | Space: O(capacity)

Python Implementation

class Node: def __init__(self, key=0, val=0): self.key = key self.val = val self.prev = None self.next = None class LRUCache: def __init__(self, capacity: int): self.capacity = capacity self.map = {} self.head = Node() # MRU sentinel self.tail = Node() # LRU sentinel self.head.next = self.tail self.tail.prev = self.head def _add_front(self, node: Node) -> None: node.next = self.head.next node.prev = self.head self.head.next.prev = node self.head.next = node def _remove(self, node: Node) -> None: p, n = node.prev, node.next p.next = n n.prev = p def _move_to_front(self, node: Node) -> None: self._remove(node) self._add_front(node) def get(self, key: int) -> int: node = self.map.get(key) if not node: return -1 self._move_to_front(node) return node.val def put(self, key: int, value: int) -> None: if key in self.map: node = self.map[key] node.val = value self._move_to_front(node) return node = Node(key, value) self.map[key] = node self._add_front(node) if len(self.map) > self.capacity: lru = self.tail.prev self._remove(lru) del self.map[lru.key]

JavaScript Implementation

class Node { constructor(key = 0, val = 0) { this.key = key; this.val = val; this.prev = null; this.next = null; } } class LRUCache { constructor(capacity) { this.capacity = capacity; this.map = new Map(); this.head = new Node(); this.tail = new Node(); this.head.next = this.tail; this.tail.prev = this.head; } addFront(node) { node.next = this.head.next; node.prev = this.head; this.head.next.prev = node; this.head.next = node; } remove(node) { const p = node.prev; const n = node.next; p.next = n; n.prev = p; } moveToFront(node) { this.remove(node); this.addFront(node); } get(key) { if (!this.map.has(key)) return -1; const node = this.map.get(key); this.moveToFront(node); return node.val; } put(key, value) { if (this.map.has(key)) { const node = this.map.get(key); node.val = value; this.moveToFront(node); return; } const node = new Node(key, value); this.map.set(key, node); this.addFront(node); if (this.map.size > this.capacity) { const lru = this.tail.prev; this.remove(lru); this.map.delete(lru.key); } } }

🔍 Step-by-Step Walkthrough

capacity=2, put(1,1), put(2,2), get(1), put(3,3):

⚡ Complexity Analysis

get: O(1) map lookup + O(1) list move.

put: O(1) update/insert + optional O(1) tail eviction.

Space: O(capacity).

🔧 Edge Cases

🧪 Test Cases

Expected outputs

💼 Interview Tips

🎓 Key Takeaways

← Back to All Algorithms