Katkat

Design and implement an LRU cache

NVIDIASoftware Engineer · Technical Screen

Last updated

This problem tests your ability to design a cache that supports O(1) time complexity for both insertions and lookups by combining a hash map with a doubly linked list.

Problem Statement

Design and implement a data structure for a Least Recently Used (LRU) cache. The cache should support the following operations:

  • get(key): Return the value of the key if it exists in the cache, otherwise return -1. Accessing a key makes it the most recently used.
  • put(key, value): Update or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least recently used item before inserting a new item.

Your implementation must support both get and put operations in O(1) average time complexity.

Implementation Signature

class LRUCache:
    def __init__(self, capacity: int):
        # Initialize the LRU cache with positive size capacity
        pass

    def get(self, key: int) -> int:
        # Return value if exists, else -1
        pass

    def put(self, key: int, value: int) -> None:
        # Update value or insert new key-value pair
        pass

Example

lru = LRUCache(2)
lru.put(1, 1) # Cache: {1:1}
lru.put(2, 2) # Cache: {1:1, 2:2}
lru.get(1)    # Returns 1. Cache: {2:2, 1:1} (1 is now MRU)
lru.put(3, 3) # Evicts key 2. Cache: {1:1, 3:3}
lru.get(2)    # Returns -1 (not found)

Constraints

  • capacity will be between 1 and 1000.
  • key and value are non-negative integers.
  • Ensure the solution handles empty cache states and eviction correctly.

Hints

Hint 1

To achieve O(1) lookups, use a hash map to store keys and their corresponding node references.

Hint 2

To maintain the order of usage, use a doubly linked list where the head represents the most recently used item and the tail the least recently used.

Hint 3

When updating a key or performing a get, move the accessed node to the head of the linked list to mark it as the most recently used.

Follow-up questions

  • How would you make this implementation thread-safe for a multi-threaded environment?
  • What would change if you needed to implement an LFU (Least Frequently Used) cache instead?
  • If the cache capacity is very large (e.g., millions of entries), what memory considerations should you keep in mind regarding the doubly linked list nodes?