Practice
Solution
Step 1: Understand the eviction criteria
The cache must evict the least frequently used key, and if multiple keys share the same frequency, evict the least recently used among them.Step 2: Identify data structures supporting O(1) operations
A frequency map with doubly linked lists allows grouping keys by frequency and maintaining recency order within each frequency group, enabling O(1) updates and eviction.Final Answer:
Option B -> Option BQuick Check:
Frequency map + doubly linked lists is the classic LFU O(1) approach [OK]
- Using sorting on eviction is too slow
- Min-heap adds O(log n) overhead
- Single list can't maintain frequency and recency efficiently
addRange method snippet from the optimal RangeModule implementation, what is the value of self.starts after calling addRange(2, 6) on an initially empty RangeModule?
def addRange(self, left: int, right: int) -> None:
i = bisect_left(self.starts, left)
j = bisect_right(self.starts, right)
if i != 0 and self.intervals[self.starts[i-1]] >= left:
i -= 1
left = min(left, self.starts[i])
if j != 0:
right = max(right, self.intervals[self.starts[j-1]])
for k in self.starts[i:j]:
del self.intervals[k]
self.starts[i:j] = [left]
self.intervals[left] = right
Solution
Step 1: Trace bisect indices on empty starts list
Initially,self.starts = []. Callingbisect_left([], 2)returns 0, andbisect_right([], 6)returns 0.Step 2: Update intervals and starts
Sincei == 0, the first if condition is skipped. Also,j == 0, so second if is skipped. No intervals to delete. Insertleft=2atself.starts[0:0], soself.starts = [2]. Interval stored as{2:6}.Final Answer:
Option C -> Option CQuick Check:
Starts list after first addRange is [2] [OK]
- Assuming right endpoint is also inserted in starts list
Solution
Step 1: Identify auxiliary data structures
The optimal approach does not use hash maps or arrays; it weaves copied nodes into the original list.Step 2: Analyze space usage
Only a few pointers are used; no extra space proportional to n is allocated, so space complexity is O(1).Final Answer:
Option A -> Option AQuick Check:
No hash maps or recursion stacks used [OK]
- Assuming hash map is always needed, so O(n) space
- Confusing recursion stack space with iterative approach
- Thinking auxiliary arrays are used for random pointers
import bisect
class SnapshotArray:
def __init__(self, length: int):
self.snap_id = 0
self.data = [[(-1, 0)] for _ in range(length)]
def set(self, index: int, val: int) -> None:
# Bug here
self.data[index].append((self.snap_id, val))
def snap(self) -> int:
self.snap_id += 1
return self.snap_id - 1
def get(self, index: int, snap_id: int) -> int:
arr = self.data[index]
i = bisect.bisect_right(arr, (snap_id, float('inf'))) - 1
return arr[i][1]
Solution
Step 1: Analyze set() method
The set method always appends (snap_id, val) without checking if the last entry has the same snap_id, causing duplicate entries for the same snap_id.Step 2: Consequence on get()
Duplicate entries for the same snap_id break binary search assumptions and can cause get to return incorrect values.Final Answer:
Option C -> Option CQuick Check:
Correct code replaces last entry if snap_id matches [OK]
- Appending blindly causes duplicates
- Misunderstanding initialization defaults
Solution
Step 1: Consider negative coordinates impact
Bisect operations and interval storage must correctly handle negative values, which requires no change in data structure but careful handling of interval boundaries.Step 2: Consider interval reuse
Intervals can be added and removed multiple times, so storing intervals as half-open [start, end) and merging intervals correctly remains essential.Final Answer:
Option D -> Option DQuick Check:
Adjust bisect and interval representation for negatives and reuse [OK]
- Thinking data structure must change to segment tree unnecessarily
