Bird
Raised Fist0
Interview Prepcustom-data-structuresmediumAmazonFacebookGoogleMicrosoftBloomberg

LRU Cache

Choose your preparation mode4 modes available
</>
IDE
class LRUCache: def __init__(self, capacity: int): pass def get(self, key: int) -> int: pass def put(self, key: int, value: int) -> None: passpublic class LRUCache { public LRUCache(int capacity) {} public int get(int key) { return 0; } public void put(int key, int value) {} }class LRUCache { public: LRUCache(int capacity) {} int get(int key) { return 0; } void put(int key, int value) {} };class LRUCache { constructor(capacity) {} get(key) { return 0; } put(key, value) {} }
class LRUCache:
    def __init__(self, capacity: int):
        pass
    def get(self, key: int) -> int:
        pass
    def put(self, key: int, value: int) -> None:
        pass
public class LRUCache {
    public LRUCache(int capacity) {
    }
    public int get(int key) {
        return -1;
    }
    public void put(int key, int value) {
    }
}
class LRUCache {
public:
    LRUCache(int capacity) {
    }
    int get(int key) {
        return -1;
    }
    void put(int key, int value) {
    }
};
class LRUCache {
    constructor(capacity) {
    }
    get(key) {
        return -1;
    }
    put(key, value) {
    }
}
Coming soon
0/10
Common Bugs to Avoid
Wrong: get returns stale value or -1 incorrectly after put of existing keyput does not update value or usage order for existing keys✅ In put, if key exists, update value and move node to front of usage list
Wrong: Evicted wrong key after get operationget does not update usage order, so eviction removes wrong key✅ In get, move accessed node to front of usage list before returning value
Wrong: Cache size exceeds capacity or no eviction occursEviction logic missing or incorrect when capacity exceeded✅ Before inserting new key, remove tail node of usage list and delete from map if capacity reached
Wrong: TLE on large inputUsing list removal or linear scans in get/put causing O(n) per operation✅ Use doubly linked list with hash map to achieve O(1) get and put
✓
Test Cases
t1_01basic
Input["LRUCache cache = new LRUCache(2);","cache.put(1, 1);","cache.put(2, 2);","cache.get(1);","cache.put(3, 3);","cache.get(2);","cache.put(4, 4);","cache.get(1);","cache.get(3);","cache.get(4);"]
Expected[null,null,null,1,null,-1,null,-1,3,4]

Cache capacity is 2. After putting keys 1 and 2, get(1) returns 1 and makes key 1 most recently used. Putting key 3 evicts key 2. get(2) returns -1 because key 2 was evicted. Putting key 4 evicts key 1. get(1) returns -1, get(3) returns 3, get(4) returns 4.

t1_02basic
Input["LRUCache cache = new LRUCache(3);","cache.put(1, 10);","cache.put(2, 20);","cache.put(3, 30);","cache.get(2);","cache.put(4, 40);","cache.get(1);","cache.get(3);","cache.get(4);"]
Expected[null,null,null,null,20,null,-1,30,40]

Capacity 3 cache stores keys 1,2,3. get(2) returns 20 and makes key 2 most recently used. put(4,40) evicts least recently used key 1. get(1) returns -1, get(3) returns 30, get(4) returns 40.

t2_01edge
Input["LRUCache cache = new LRUCache(1);","cache.put(1, 100);","cache.get(1);","cache.put(2, 200);","cache.get(1);","cache.get(2);"]
Expected[null,null,100,null,-1,200]

Capacity 1 cache evicts immediately on new put. After put(1,100), get(1) returns 100. put(2,200) evicts key 1. get(1) returns -1, get(2) returns 200.

t2_02edge
Input["LRUCache cache = new LRUCache(2);","cache.get(42);"]
Expected[-1]

Getting a key that was never added returns -1.

t2_03edge
Input["LRUCache cache = new LRUCache(2);","cache.put(1, 10);","cache.put(1, 20);","cache.get(1);"]
Expected[null,null,20]

Putting the same key multiple times updates its value and usage order. get(1) returns updated value 20.

t2_04edge
Input["LRUCache cache = new LRUCache(2);","cache.put(1, 1);","cache.put(2, 2);","cache.put(3, 3);","cache.get(1);","cache.get(2);","cache.get(3);"]
Expected[null,null,null,null,-1,2,3]

Put keys until capacity, then put one more evicts least recently used key 1. get(1) returns -1, get(2) returns 2, get(3) returns 3.

t3_01corner
Input["LRUCache cache = new LRUCache(2);","cache.put(1, 1);","cache.put(2, 2);","cache.get(1);","cache.get(2);","cache.put(3, 3);","cache.get(1);","cache.get(2);","cache.get(3);"]
Expected[null,null,null,1,2,null,-1,2,3]

Tests greedy trap: evicting wrong key if not updating usage order on get. get(1) and get(2) update usage order; put(3) evicts key 1 as least recently used after get(1) and get(2).

t3_02corner
Input["LRUCache cache = new LRUCache(2);","cache.put(1, 1);","cache.put(2, 2);","cache.put(1, 10);","cache.put(3, 3);","cache.get(1);","cache.get(2);","cache.get(3);"]
Expected[null,null,null,null,null,10,-1,3]

Tests 0/1 confusion: put updates existing key value and usage order, so key 1 is most recent. put(3) evicts key 2. get(1) returns updated 10, get(2) returns -1.

t3_03corner
Input["LRUCache cache = new LRUCache(3);","cache.put(1, 1);","cache.put(2, 2);","cache.put(3, 3);","cache.get(2);","cache.put(4, 4);","cache.get(3);","cache.get(1);","cache.get(4);"]
Expected[null,null,null,null,2,null,3,-1,4]

Tests off-by-one errors in eviction: after get(2), key 2 is most recent; put(4) evicts key 1. get(1) returns -1, get(3) returns 3, get(4) returns 4.

t4_01performance
Input{"capacity":100,"operations":[{"op":"put","key":0,"value":0},{"op":"put","key":1,"value":10},{"op":"put","key":2,"value":20},{"op":"put","key":3,"value":30},{"op":"put","key":4,"value":40},{"op":"put","key":5,"value":50},{"op":"put","key":6,"value":60},{"op":"put","key":7,"value":70},{"op":"put","key":8,"value":80},{"op":"put","key":9,"value":90},{"op":"put","key":10,"value":100},{"op":"put","key":11,"value":110},{"op":"put","key":12,"value":120},{"op":"put","key":13,"value":130},{"op":"put","key":14,"value":140},{"op":"put","key":15,"value":150},{"op":"put","key":16,"value":160},{"op":"put","key":17,"value":170},{"op":"put","key":18,"value":180},{"op":"put","key":19,"value":190},{"op":"put","key":20,"value":200},{"op":"put","key":21,"value":210},{"op":"put","key":22,"value":220},{"op":"put","key":23,"value":230},{"op":"put","key":24,"value":240},{"op":"put","key":25,"value":250},{"op":"put","key":26,"value":260},{"op":"put","key":27,"value":270},{"op":"put","key":28,"value":280},{"op":"put","key":29,"value":290},{"op":"put","key":30,"value":300},{"op":"put","key":31,"value":310},{"op":"put","key":32,"value":320},{"op":"put","key":33,"value":330},{"op":"put","key":34,"value":340},{"op":"put","key":35,"value":350},{"op":"put","key":36,"value":360},{"op":"put","key":37,"value":370},{"op":"put","key":38,"value":380},{"op":"put","key":39,"value":390},{"op":"put","key":40,"value":400},{"op":"put","key":41,"value":410},{"op":"put","key":42,"value":420},{"op":"put","key":43,"value":430},{"op":"put","key":44,"value":440},{"op":"put","key":45,"value":450},{"op":"put","key":46,"value":460},{"op":"put","key":47,"value":470},{"op":"put","key":48,"value":480},{"op":"put","key":49,"value":490},{"op":"put","key":50,"value":500},{"op":"put","key":51,"value":510},{"op":"put","key":52,"value":520},{"op":"put","key":53,"value":530},{"op":"put","key":54,"value":540},{"op":"put","key":55,"value":550},{"op":"put","key":56,"value":560},{"op":"put","key":57,"value":570},{"op":"put","key":58,"value":580},{"op":"put","key":59,"value":590},{"op":"put","key":60,"value":600},{"op":"put","key":61,"value":610},{"op":"put","key":62,"value":620},{"op":"put","key":63,"value":630},{"op":"put","key":64,"value":640},{"op":"put","key":65,"value":650},{"op":"put","key":66,"value":660},{"op":"put","key":67,"value":670},{"op":"put","key":68,"value":680},{"op":"put","key":69,"value":690},{"op":"put","key":70,"value":700},{"op":"put","key":71,"value":710},{"op":"put","key":72,"value":720},{"op":"put","key":73,"value":730},{"op":"put","key":74,"value":740},{"op":"put","key":75,"value":750},{"op":"put","key":76,"value":760},{"op":"put","key":77,"value":770},{"op":"put","key":78,"value":780},{"op":"put","key":79,"value":790},{"op":"put","key":80,"value":800},{"op":"put","key":81,"value":810},{"op":"put","key":82,"value":820},{"op":"put","key":83,"value":830},{"op":"put","key":84,"value":840},{"op":"put","key":85,"value":850},{"op":"put","key":86,"value":860},{"op":"put","key":87,"value":870},{"op":"put","key":88,"value":880},{"op":"put","key":89,"value":890},{"op":"put","key":90,"value":900},{"op":"put","key":91,"value":910},{"op":"put","key":92,"value":920},{"op":"put","key":93,"value":930},{"op":"put","key":94,"value":940},{"op":"put","key":95,"value":950},{"op":"put","key":96,"value":960},{"op":"put","key":97,"value":970},{"op":"put","key":98,"value":980},{"op":"put","key":99,"value":990},{"op":"get","key":0},{"op":"get","key":50},{"op":"get","key":99}]}
⏱ Performance - must finish in 2000ms

Performance test with capacity=100 and 100 put operations followed by 3 get operations to ensure O(1) operations complete within 2 seconds.

Practice

(1/5)
1. You need to design a data structure that supports incrementing and decrementing string keys, and retrieving a key with the maximum or minimum count, all in constant time. Which approach best guarantees O(1) time complexity for all these operations?
easy
A. Using a balanced binary search tree keyed by counts to maintain order of keys
B. Using a hash map to store counts and scanning all keys to find max/min when requested
C. Maintaining a doubly linked list of buckets, each bucket holding keys with the same count, plus hash maps for quick access
D. Using a priority queue to track max and min keys with lazy updates

Solution

  1. Step 1: Understand operation requirements

    Increment, decrement, getMaxKey, and getMinKey must all be O(1).
  2. Step 2: Evaluate approaches

    Hash map + linear scan (B) is O(n) for max/min. Balanced BST (C) and priority queue (D) have O(log n) operations. Doubly linked list with buckets and hash maps (A) supports O(1) updates and retrievals.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Bucket list + hash maps enable O(1) increments, decrements, and max/min retrievals [OK]
Hint: Bucket list + hash maps enable O(1) max/min updates [OK]
Common Mistakes:
  • Thinking balanced BST or priority queue can achieve O(1) for all operations
2. Consider the following Python code implementing the optimal CustomStack with lazy increments. After executing the sequence of operations below, what is the output of the last pop() call?
cs = CustomStack(3)
cs.push(1)
cs.push(2)
cs.increment(2, 5)
print(cs.pop())
easy
A. 2
B. 7
C. 6
D. 1

Solution

  1. Step 1: Trace the increment operation

    After pushing 1 and 2, stack = [1, 2], inc = [0, 0, 0]. increment(2, 5) sets inc[1] += 5 -> inc = [0, 5, 0].
  2. Step 2: Trace the pop operation

    pop() removes top element at index 1 (value 2). Since i=1 > 0, inc[0] += inc[1] -> inc[0] = 0 + 5 = 5. Result = stack.pop() + inc[1] = 2 + 5 = 7. inc[1] reset to 0.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Increment applied lazily, pop returns 7 [OK]
Hint: Increment applies to inc array index k-1, added on pop [OK]
Common Mistakes:
  • Forgetting to propagate increments down on pop
  • Adding increments directly to popped element only
3. Consider the following partial Skiplist search method code. After inserting values 1, 3, and 7, what will be the value of curr.val after the outer loop finishes when searching for target = 3?
easy
A. 7
B. 1
C. 3
D. -1

Solution

  1. Step 1: Trace outer loop from highest to lowest level

    At each level, move forward while next node's value is less than 3. After finishing, curr points to node with value just less than or equal to 3.
  2. Step 2: Move curr to forward[0]

    After the loop, curr moves to forward[0], which should be node with value 3 if it exists.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Search finds node with value 3 exactly [OK]
Hint: Search stops at node before target, then moves forward once [OK]
Common Mistakes:
  • Off-by-one error in loop
  • Confusing curr position before and after loop
  • Assuming curr stays at head
4. Consider the following Python code snippet for the MedianFinder class using two heaps. After adding the numbers 1, 5, and 3 in that order, what is the value of the median returned by findMedian()?
easy
A. 1.0
B. 3.0
C. 5.0
D. 2.0

Solution

  1. Step 1: Insert 1

    Low heap empty, push -1 to low; low_size=1, high_size=0.
  2. Step 2: Insert 5

    5 > -low[0] (which is 1), push 5 to high; low_size=1, high_size=1; heaps balanced.
  3. Step 3: Insert 3

    3 <= 5 but > 1, push 3 to high; high_size=2, low_size=1; balance heaps by moving smallest from high (3) to low (-3); low_size=2, high_size=1.
  4. Step 4: Find median

    low_size > high_size, median is -low[0] = 3.0.
  5. Step 5: Re-examine median calculation

    After balancing, low heap has [-3, -1], high heap has [5]. Median is top of low heap = 3.0, but the question asks for median after adding 1,5,3 in order, so median is 3.0.
  6. Final Answer:

    Option B -> Option B
  7. Quick Check:

    Median after [1,5,3] is 3.0 [OK]
Hint: Median is top of larger heap after balancing [OK]
Common Mistakes:
  • Forgetting to balance heaps after insertion
  • Returning wrong heap top for median
5. Given the following code snippet for SnapshotArray, what is the output of snapshotArr.get(0, 0) after executing all lines shown?
snapshotArr = SnapshotArray(3)
snapshotArr.set(0, 5)
snap_id = snapshotArr.snap()
snapshotArr.set(0, 6)
print(snapshotArr.get(0, 0))
easy
A. 5
B. 6
C. 0
D. Error due to invalid snap_id

Solution

  1. Step 1: Trace set and snap operations

    Initially, data[0] = [(-1,0)]. After set(0,5), data[0] = [(-1,0),(0,5)] because snap_id=0. Then snap() increments snap_id to 1 and returns 0. Then set(0,6) appends (1,6) to data[0].
  2. Step 2: Trace get(0,0)

    For snap_id=0, bisect_right finds insertion point for (0,inf) in data[0] = [(-1,0),(0,5),(1,6)]. It returns index 2, so i=1. data[0][1] = (0,5), so get returns 5.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Value at snap 0 is 5, not the later set 6 [OK]
Hint: Get returns value at or before snap_id using binary search [OK]
Common Mistakes:
  • Returning latest value ignoring snap_id
  • Off-by-one in bisect index
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard