Asked at Jane Street, Citadel Securities
Theory: Data Structures You Implement, Not ImportRead the problem, hints and solution here. The editor needs a bigger screen: open this page on a laptop to write and run your code.
Every pricing service ends up with a cache in front of it: symbol metadata, curve snapshots, reference data that is expensive to fetch and mostly read. The classic interview version is the LRU cache, and interviewers like to bolt on a twist once the first version works. Here the twist is announced up front, so design for it.
Implement a class LRUCache(capacity) with three methods:
get(key): return the value stored under key and mark the key most
recently used, or -1 if the key is absent.put(key, value): insert or update key; an update also marks the key
most recently used. If inserting a new key would exceed capacity, evict
the least-recently-used key first.get_stale(): return the least-recently-used key, the one put would
evict next, without evicting it and without changing any recency order.
Return -1 if the cache is empty.The tests drive your class through the run_ops(capacity, ops) driver
already in the scaffold (do not modify it): each op is ("get", key),
("put", key, value) or ("get_stale",), and the driver records one output
per op, with None recorded for puts.
run_ops(2, [("put", 1, 10), ("put", 2, 20), ("get", 1), ("get_stale",), ("put", 3, 30), ("get", 2), ("get", 3)])
# [None, None, 10, 2, None, -1, 30]
# get(1) refreshes key 1, so key 2 is the stale one and gets evicted by put(3, 30)
run_ops(2, [("get_stale",), ("put", 1, 1), ("put", 2, 2), ("put", 1, 99), ("put", 3, 3), ("get", 1), ("get", 2), ("get_stale",)])
# [-1, None, None, None, None, 99, -1, 3]
# get_stale on an empty cache is -1; updating key 1 refreshes it, so put(3, 3)
# evicts key 2; after get(1) the least-recently-used key is 3
1 <= capacity <= 50000; up to \(2 \times 10^5\) operations.-1 is unambiguous.Run your code to check it against the sample tests. Results appear here.