💡 The Twitter object starts empty, ready to record tweets and follows.
insert
Post Tweet: User 1 posts Tweet 5
Increment global time to 1. Create a new TweetNode with tweetId=5 and time=1. Set its next pointer to current head of user 1's tweets (none). Update user 1's tweet head to this new node.
💡 Posting a tweet adds a new node at the head of the user's tweet linked list, keeping newest tweets first.
Design Twitter (Top K Recent Tweets) - Watch the Algorithm Execute, Step by Step
Watching each pointer and heap operation live reveals how the linked list and heap combine to efficiently produce the news feed, which is hard to grasp from code alone.
Step 1/10
·Active fill★Answer cell
advance
insert
Tweet Id:5
Time:1
advance
Tweet Id:5
Time:1
insert
Tweet Id:5
Time:1
detach
Tweet Id:5
Time:1
Result: [5]
advance
Tweet Id:5
Time:1
Result: [5]
advance
Tweet Id:5
Time:1
Result: [5]
advance
Tweet Id:5
Time:1
Result: [5]
advance
Tweet Id:5
Time:1
advance
Tweet Id:5
Time:1
Result: [5]
Key Takeaways
✓ Tweets are stored as linked lists per user with newest tweets at the head.
This structure allows O(1) insertion and easy traversal from newest to oldest tweets.
✓ The news feed merges multiple users' tweet lists using a max heap keyed by timestamp.
This merging efficiently retrieves the top recent tweets across all followees without scanning all tweets.
✓ Each step of heap push/pop and linked list traversal corresponds to one meaningful operation in the algorithm.
Seeing these operations individually clarifies how the algorithm maintains the correct order and stops correctly.
Practice
(1/5)
1. 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
Step 1: Insert 1
Low heap empty, push -1 to low; low_size=1, high_size=0.
Step 2: Insert 5
5 > -low[0] (which is 1), push 5 to high; low_size=1, high_size=1; heaps balanced.
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.
Step 4: Find median
low_size > high_size, median is -low[0] = 3.0.
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.
Final Answer:
Option B -> Option B
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
2. Given the following 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
Since i == 0, the first if condition is skipped. Also, j == 0, so second if is skipped. No intervals to delete. Insert left=2 at self.starts[0:0], so self.starts = [2]. Interval stored as {2:6}.
Final Answer:
Option C -> Option C
Quick Check:
Starts list after first addRange is [2] [OK]
Hint: Bisect on empty list returns 0, so starts list gets single element [OK]
Common Mistakes:
Assuming right endpoint is also inserted in starts list
3. What is the time complexity of the inc and dec operations in the optimized AllOne data structure that uses doubly linked list buckets and hash maps, and why?
medium
A. O(1) worst-case because all operations involve only pointer and hash map updates
B. O(1) amortized because bucket insertion and removal are constant time with hash maps
C. O(log n) due to maintaining sorted order of buckets
D. O(n) because updating buckets requires scanning keys
Solution
Step 1: Identify operations involved in inc/dec
Operations include moving keys between buckets, inserting/removing buckets, and updating hash maps.
Step 2: Analyze complexity of each operation
All pointer updates and hash map lookups/inserts/removals are O(1). No scanning or sorting is needed.
Final Answer:
Option A -> Option A
Quick Check:
All operations are pointer and hash map updates, no loops over keys [OK]
Hint: Pointer and hash map ops are O(1), no scanning or sorting [OK]
Common Mistakes:
Confusing bucket insertion as O(log n) or scanning keys as O(n)
4. The following code attempts to copy a linked list with random pointers using the optimal weaving approach. Identify the line that contains a subtle bug that can cause incorrect random pointer assignment or list corruption.
def copyRandomList(head):
if not head:
return None
curr = head
# Step 1: Insert copied nodes
while curr:
new_node = Node(curr.val, curr.next)
curr.next = new_node
curr = new_node.next
# Step 2: Assign random pointers
curr = head
while curr:
if curr.random:
curr.next.random = curr.random # Bug here
curr = curr.next.next
# Step 3: Separate lists
curr = head
copy_head = head.next
copy_curr = copy_head
while curr:
curr.next = curr.next.next
if copy_curr.next:
copy_curr.next = copy_curr.next.next
curr = curr.next
copy_curr = copy_curr.next
return copy_head
medium
A. Line assigning curr.next.random = curr.random
B. Line inserting copied nodes: curr.next = new_node
C. Line advancing curr in Step 1: curr = new_node.next
D. Line separating original and copied lists: curr.next = curr.next.next
Solution
Step 1: Analyze random pointer assignment
The line assigns curr.next.random = curr.random, but curr.random points to original nodes, not copied nodes.
Step 2: Correct assignment
It should be curr.next.random = curr.random.next to point to the copied node corresponding to curr.random.
Final Answer:
Option A -> Option A
Quick Check:
Incorrect random pointer assignment breaks copied list correctness [OK]
Hint: Random pointer must point to copied node, not original [OK]
Common Mistakes:
Assigning random pointer directly to original node
Mixing original and copied nodes after weaving
Forgetting to advance curr by two nodes
5. Examine the following buggy remove method from the optimized Insert Delete GetRandom O(1) with duplicates data structure. Which line contains the subtle bug that can cause incorrect behavior or runtime errors?
def remove(self, val: int) -> bool:
if val not in self.idx_map or not self.idx_map[val]:
return false
remove_idx = self.idx_map[val].pop()
last_val = self.nums[-1]
self.nums[remove_idx] = last_val
self.idx_map[last_val].add(remove_idx)
# BUG: missing discard of old index for last_val
self.nums.pop()
if not self.idx_map[val]:
del self.idx_map[val]
return true
medium
A. Missing line to discard old index of last_val from idx_map[last_val]
B. Line adding remove_idx to idx_map[last_val] (self.idx_map[last_val].add(remove_idx))
C. Line popping remove_idx from idx_map[val] (remove_idx = self.idx_map[val].pop())
D. Line removing the last element from nums (self.nums.pop())
Solution
Step 1: Understand index updates during removal
When swapping last_val into remove_idx, we must update idx_map[last_val] by adding remove_idx and discarding the old index (len(nums)-1).
Step 2: Identify missing discard
The code adds remove_idx to idx_map[last_val] but does not discard the old index, causing stale indices and incorrect removals later.
Final Answer:
Option A -> Option A
Quick Check:
Missing discard leads to incorrect index tracking [OK]
Hint: Always discard old indices after swapping during removal [OK]