Track your progress, run tests, and get AI feedback
Run code and see test results
Submit and get AI-powered feedback
Track which problems you've solved
Design a Capacity-Aware LRU Cache with Variable Item Sizes
This problem challenges you to design a Least Recently Used (LRU) cache that manages items with varying memory sizes, instead of a fixed count. This requires the cache to consider total occupied capacity rather than just the number of entries when making eviction decisions. Implementing this CapacityAwareLRUCache will strengthen your understanding of hash maps and doubly linked lists for efficient cache management.
Implement the CapacityAwareLRUCache class with the following methods:
constructor(capacity: number): Initializes the cache with a total byte capacity. This is the maximum sum of sizes of all items the cache can hold.get(key: number): number: Retrieves the value associated with key. If key exists in the cache, return its value and mark it as recently used. Otherwise, return -1.put(key: number, value: number, size: number): void: Inserts or updates an item in the cache. The size parameter indicates the memory footprint of the item.
key already exists, update its value and size, then mark it as recently used.key does not exist, add the new key-value pair with its size.size of a new item (or the new size of an updated item) is greater than the cache's total capacity, that item cannot be stored or updated. In such a case, for a new item, do nothing. For an existing item, its value and size should not be updated, and it remains in its current state and position.capacity, evict the least recently used items until enough space is freed. Items must be evicted one by one, starting from the least recently used.The problem requires you to implement a class CapacityAwareLRUCache.
class CapacityAwareLRUCache {
constructor(capacity: number);
get(key: number): number;
put(key: number, value: number, size: number): void;
}
Operations will be provided as an array of method calls, and parameters as an array of arrays.
Input Format:
operations = ["CapacityAwareLRUCache", "put", "put", "get", ...], params = [[capacity], [key, value, size], [key, value, size], [key], ...]
Output Format:
An array of results for get operations, or null for constructor and put operations.
key, value, size, and capacity?
key, value, size, and capacity will be positive integers, except for capacity which can be 0.capacity is 0?
capacity is 0, the cache cannot store any items. put operations will effectively do nothing, and get operations will always return -1.size (during a put operation for an existing item) is smaller than its old size, does it still count as being 'recently used'?
put or get operation on an existing key marks it as recently used, moving it to the front of the LRU order, as long as the update is valid (i.e., new size doesn't exceed total capacity).Examples
Example 1
Input:
operations = ["CapacityAwareLRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"], params = [[2], [1, 1, 1], [2, 2, 1], [1], [3, 3, 1], [2], [4, 4, 1], [1], [3], [4]]
Output:
[null, null, null, 1, null, -1, null, -1, 3, 4]
Note:
Initialize cache with capacity 2.
put(1, 1, 1): Cache: {1: (1, size=1)}. Current capacity: 1. LRU order: [1]put(2, 2, 1): Cache: {2: (2, size=1), 1: (1, size=1)}. Current capacity: 2. LRU order: [2, 1]get(1): Returns 1. Cache: {1: (1, size=1), 2: (2, size=1)}. Current capacity: 2. LRU order: [1, 2]put(3, 3, 1): New item (size=1) + Current capacity (2) = 3. Exceeds max capacity (2).
Evict LRU: 2 (size=1). Current capacity becomes 2-1=1.
Add 3 (size=1). Current capacity becomes 1+1=2.
Cache: {3: (3, size=1), 1: (1, size=1)}. Current capacity: 2. LRU order: [3, 1]get(2): Returns -1 (2 was evicted).put(4, 4, 1): New item (size=1) + Current capacity (2) = 3. Exceeds max capacity (2).
Evict LRU: 1 (size=1). Current capacity becomes 2-1=1.
Add 4 (size=1). Current capacity becomes 1+1=2.
Cache: {4: (4, size=1), 3: (3, size=1)}. Current capacity: 2. LRU order: [4, 3]get(1): Returns -1 (1 was evicted).get(3): Returns 3. Cache: {3: (3, size=1), 4: (4, size=1)}. Current capacity: 2. LRU order: [3, 4]get(4): Returns 4. Cache: {4: (4, size=1), 3: (3, size=1)}. Current capacity: 2. LRU order: [4, 3]Example 2
Input:
operations = ["CapacityAwareLRUCache", "put", "put", "put", "put", "get", "put", "get", "get", "get"], params = [[3], [1, 10, 1], [2, 20, 2], [3, 30, 1], [4, 40, 2], [2], [5, 50, 1], [1], [3], [4]]
Output:
[null, null, null, null, null, -1, null, -1, -1, 40]
Note:
Initialize cache with capacity 3.
put(1, 10, 1): Cache: {1: (10, s=1)}. CurrCap: 1. LRU: [1]put(2, 20, 2): Cache: {2: (20, s=2), 1: (10, s=1)}. CurrCap: 3. LRU: [2, 1]put(3, 30, 1): New (s=1). CurrCap (3) + s (1) = 4 > Cap (3).
Evict 1 (s=1). CurrCap: 3-1=2.
Add 3 (s=1). CurrCap: 2+1=3.
Cache: {3: (30, s=1), 2: (20, s=2)}. LRU: [3, 2]put(4, 40, 2): New (s=2). CurrCap (3) + s (2) = 5 > Cap (3).
Evict 2 (s=2). CurrCap: 3-2=1.
Add 4 (s=2). CurrCap: 1+2=3.
Cache: {4: (40, s=2), 3: (30, s=1)}. LRU: [4, 3]get(2): Returns -1 (2 was evicted).put(5, 50, 1): New (s=1). CurrCap (3) + s (1) = 4 > Cap (3).
Evict 3 (s=1). CurrCap: 3-1=2.
Add 5 (s=1). CurrCap: 2+1=3.
Cache: {5: (50, s=1), 4: (40, s=2)}. LRU: [5, 4]get(1): Returns -1 (1 was evicted).get(3): Returns -1 (3 was evicted).get(4): Returns 40. Cache: {4: (40, s=2), 5: (50, s=1)}. LRU: [4, 5]Example 3
Input:
operations = ["CapacityAwareLRUCache", "put", "put", "put", "get", "put", "get", "put", "get"], params = [[5], [1, 10, 3], [2, 20, 4], [3, 30, 6], [3], [2, 25, 2], [2], [2, 26, 7], [2]]
Output:
[null, null, null, null, -1, null, 25, null, 25]
Note:
Initialize cache with capacity 5.
put(1, 10, 3): Cache: {1: (10, s=3)}. CurrCap: 3. LRU: [1]put(2, 20, 4): New (s=4). CurrCap (3) + s (4) = 7 > Cap (5).
Evict 1 (s=3). CurrCap: 3-3=0.
Add 2 (s=4). CurrCap: 0+4=4.
Cache: {2: (20, s=4)}. CurrCap: 4. LRU: [2]put(3, 30, 6): New item (s=6) > Cap (5). Do nothing. Cache unchanged. CurrCap: 4. LRU: [2]get(3): Returns -1 (not in cache).put(2, 25, 2): Update existing item 2. New size 2. Old size 4.
New size 2 is not > Cap (5). Valid update.
currentCapacityUsed changes from 4 to 4 - 4 + 2 = 2.
Cache: {2: (25, s=2)}. CurrCap: 2. LRU: [2]get(2): Returns 25. Cache: {2: (25, s=2)}. CurrCap: 2. LRU: [2]put(2, 26, 7): Update existing item 2. New size 7 > Cap (5).
Do not update. Item 2 remains (25, s=2). LRU order unaffected. CurrCap: 2. LRU: [2]get(2): Returns 25. Cache: {2: (25, s=2)}. CurrCap: 2. LRU: [2]Constraints
0 <= capacity <= 10^51 <= key, value <= 10^91 <= size <= 10^5 (for individual items, unless size > capacity as per problem statement)10^5.get and put operations should run in average O(1) time complexity.get and put operations run in average O(1) time complexity.capacity and put operations for items whose size exceeds the total capacity.