146. LRU Cache 🔗
Difficulty: Medium - Tags: Design, Linked List, Hash Table
Problem Statement 📜
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 the key if the key exists, otherwise return-1.void put(int key, int value):Update the value of the key if it exists.
Add the key-value pair if the key does not exist.
If the number of keys exceeds the capacity, evict the least recently used key.
Constraints:
The functions
getandputmust run in O(1) average time complexity.
Examples 🌟
🔹 Example 1:
Input:
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]Output:
[null, null, null, 1, null, -1, null, -1, 3, 4]Explanation:
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1); // return 1
lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2); // return -1 (not found)
lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
lRUCache.get(1); // return -1 (not found)
lRUCache.get(3); // return 3
lRUCache.get(4); // return 4Constraints ⚙️
1 <= capacity <= 30000 <= key <= 10⁴0 <= value <= 10⁵At most
2 * 10⁵calls will be made togetandput.
Solution 💡
Use a combination of:
HashMap: For O(1) access to key-value pairs.
Doubly Linked List: For maintaining the order of usage (most recently used to least recently used).
Java Solution
import java.util.HashMap;
class LRUCache {
private class Node {
int key, value;
Node prev, next;
Node(int key, int value) {
this.key = key;
this.value = value;
}
}
private final int capacity;
private final HashMap<Integer, Node> map;
private final Node head, tail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.map = new HashMap<>();
this.head = new Node(0, 0);
this.tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if (map.containsKey(key)) {
Node node = map.get(key);
remove(node);
insert(node);
return node.value;
}
return -1;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
remove(map.get(key));
}
if (map.size() == capacity) {
remove(tail.prev);
}
insert(new Node(key, value));
}
private void remove(Node node) {
map.remove(node.key);
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void insert(Node node) {
map.put(node.key, node);
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
}Explanation of the Solution
Node Definition:
Each node stores a key-value pair.
Nodes are linked in both directions to allow quick removal.
HashMap:
Maps keys to nodes for O(1) access.
Doubly Linked List:
The head points to the most recently used node.
The tail points to the least recently used node.
Operations:
get: Move the node to the head of the list.put: Add the node to the head. If the cache exceeds capacity, remove the node at the tail.
Time Complexity ⏳
O(1) for both
getandputoperations.
Space Complexity 💾
O(n) for storing
nkey-value pairs in the HashMap and Doubly Linked List.
Follow-up 🧐
The solution is optimized for LRU Cache implementation with constant time complexity and minimal space usage. Further optimizations could involve concurrent data structures for multi-threaded environments.
You can find the full solution here.
Last updated
Was this helpful?