I started with the standard hashmap plus doubly linked list setup for LRU and felt pretty solid until they pushed on the TTL piece.
Start by clarifying requirements and constraints, then propose a combined data structure: a hash map for O(1) key lookup and a doubly linked list for O(1) recency updates. Explain how to handle TTL by storing expiration timestamps and lazily or actively evicting expired entries, and analyze the time complexity of each operation.
Pro tip: Mention that you can use a min-heap or a timing wheel for efficient TTL expiration, but be prepared to discuss the trade-offs with the simpler lazy approach. Also, emphasize that you would handle concurrency with fine-grained locking or sharding in a real system.
Ask about expected cache size, read/write ratio, concurrency needs, and whether TTL is per-entry or global. Confirm that get should refresh recency and that expired entries should be evicted before LRU.
Use a hash map (dictionary) for O(1) key lookup and a doubly linked list to maintain recency order (most recently used at head). Each node stores key, value, expiration timestamp, and pointers.
For get: check if key exists and not expired; if expired, remove and return -1; else move node to head and return value. For put: if key exists, update value and TTL and move to head; else insert new node at head, then evict expired entries (e.g., by scanning or using a min-heap) and if still over capacity, evict LRU tail.
Get and put are O(1) amortized with lazy expiration; active expiration may add O(log n) with a heap. Discuss trade-offs: lazy expiration is simpler but may leave expired entries until accessed; active expiration ensures timely removal but adds overhead.
Mention that for thread safety, you can use a lock per shard or a read-write lock. For large scale, consider sharding the cache and using consistent hashing.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.