◀ THE GRIND — HEAP / PRIORITY QUEUE

Design Twitter

MEDIUM✓ CHIP-TIMEDLC #355 — FULL STATEMENT ↗

The drill: A tiny social feed: post a tweet, follow or unfollow another user, and pull the 10 most recent tweets — yours and everyone you follow — newest first.

THE BRIEFING — THE FULL DRILL, IN MY OWN WORDS

A miniature social feed lets users post tweets, follow or unfollow each other, and pull their own news feed — the 10 most recent tweets from themselves and everyone they follow, newest first.

Following is one-directional and users start unfollowed from everyone; a user's feed always includes their own tweets even without explicitly following themselves.

Every action — posting, following, unfollowing, and reading the feed — has to stay responsive as the number of users and tweets grows, not just correct on a small example.

EX 01
Twitter()
postTweet(1, 5)
getNewsFeed(1) → [5]
follow(1, 2)
postTweet(2, 6)
getNewsFeed(1) → [6, 5]
unfollow(1, 2)
getNewsFeed(1) → [5]
POST, FOLLOW, POST, UNFOLLOW — FEED TRACKS EACH CHANGE
EX 02
Twitter()
postTweet(1, 101)
postTweet(1, 102)
postTweet(1, 103)
postTweet(1, 104)
postTweet(1, 105)
postTweet(1, 106)
postTweet(1, 107)
postTweet(1, 108)
postTweet(1, 109)
postTweet(1, 110)
postTweet(1, 111)
postTweet(1, 112)
getNewsFeed(1) → [112, 111, 110, 109, 108, 107, 106, 105, 104, 103]
TWELVE TWEETS FROM ONE USER — FEED TRUNCATES TO THE NEWEST 10
EX 03
Twitter()
postTweet(1, 10)
postTweet(2, 20)
follow(1, 2)
postTweet(1, 11)
getNewsFeed(1) → [11, 20, 10]
INTERLEAVED POSTS ACROSS TWO USERS, MERGED BY TIME
THE HINTS — TAKE ONLY WHAT YOU NEED
HINT 1 THE NUDGE

Every tweet needs a sense of 'when' relative to every other tweet, across every user — one global counter that only ever increases does that job.

HINT 2 THE STRUCTURE

A feed request only ever needs the freshest tail of each relevant user's tweets, not their whole history — trimming to the last 10 per user before comparing saves real work.

HINT 3 ONE STEP FROM THE ANSWER

Merge each followed user's most-recent tweets like merging sorted lists: seed a heap with one candidate per user, pop the newest, and pull that user's next-most-recent tweet in behind it, stopping once 10 are collected.

COACH'S BOARD — THE PATTERN, STEP BY STEP
MERGING TWO TIMELINESPATTERN · HEAP-MERGE RECENT TWEETSpost(1,10) · post(2,20) · follow(1,2) · post(1,11) · getNewsFeed(1)
new Twitter
u1 post 10
u2 post 20
1 follows 2
u1 post 11
feed for 1
STATE
users{}
follows{}
STEP 1

Start empty. Every tweet gets a global time stamp so we can always tell what's newest across every user.

STEP 1 / 7 · ← → WORK TOO
THE SPLITS — TWO PACES, TWO LANGUAGES
grind/design-twitter.pyRACE PACE
LANG ▸
PACE ▸
class Twitter:
    def __init__(self):
        self.time = 0
        self.userTweets = collections.defaultdict(list)  # user -> [(time, tweetId), ...]
        self.follows = collections.defaultdict(set)

    def postTweet(self, userId: int, tweetId: int) -> None:
        self.userTweets[userId].append((self.time, tweetId))
        self.time += 1

    def getNewsFeed(self, userId: int) -> List[int]:
        watch = self.follows[userId] | {userId}
        heap = []  # (-time, tweetId, user, indexIntoThatUsersList)
        for u in watch:
            lst = self.userTweets.get(u)
            if lst:
                idx = len(lst) - 1
                t, tid = lst[idx]
                heapq.heappush(heap, (-t, tid, u, idx))

        result = []
        while heap and len(result) < 10:
            _, tid, u, idx = heapq.heappop(heap)
            result.append(tid)
            if idx > 0:
                idx -= 1
                t2, tid2 = self.userTweets[u][idx]
                heapq.heappush(heap, (-t2, tid2, u, idx))
        return result

    def follow(self, followerId: int, followeeId: int) -> None:
        self.follows[followerId].add(followeeId)

    def unfollow(self, followerId: int, followeeId: int) -> None:
        self.follows[followerId].discard(followeeId)
TIME O(F LOG F) PER FEEDSPACE O(USERS + TWEETS)PYTHON · RACE PACE · 35 LN

✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED