Command Palette

Search for a command to run...

Problem 40.7 · Designing Data StructuresMedium

Design Twitter

What it teaches: A news feed is a K-way merge of followed users' tweet lists, newest first.

Practise it on judges as “Design Twitter”.

In plain words

Each person has their own pile of posts, newest on top. To build someone's feed, look at the top post of their own pile and of every pile they follow, take the newest one, then uncover the next post in that same pile. Repeat until you have 10. A max-heap is the helper that always tells you which uncovered post is newest.

Return the 10 most recent tweet ids, newest first. Example: post(1, 5); feed(1); follow(1, 2); post(2, 6); feed(1); unfollow(1, 2); feed(1) → [5], [6, 5], [5].

The problem

Design Twitter with postTweet(userId, tweetId), getNewsFeed(userId) (the 10 most recent tweet ids from the user and people they follow, newest first), follow(followerId, followeeId) and unfollow(followerId, followeeId).

Example 1

Input: post(1, 5); feed(1); follow(1, 2); post(2, 6); feed(1); unfollow(1, 2); feed(1)
Output: [5], [6, 5], [5]

Constraints

  • Up to 3 × 10⁴ calls

Pattern clues in the wording

  • → Merge several time-ordered lists, take the top 10

These clues point to Combine Structures to Design: Pair a hash map (fast lookup) with a list, heap or tree (fast ordering) to meet every operation's time limit.

Stuck? Take one hint at a time

Twitter · starter
import java.util.*;

class Twitter {
    public Twitter() {}
    public void postTweet(int userId, int tweetId) {}
    public List<Integer> getNewsFeed(int userId) { return new ArrayList<>(); }
    public void follow(int followerId, int followeeId) {}
    public void unfollow(int followerId, int followeeId) {}
}

Write your solution locally or in your editor for now. Pick Java, Python, C++, JavaScript or Go above: every solution on this page switches with it. The in-browser runner will run these tests right here.

Test cases

#InputExpected
1
ops = ["Twitter","postTweet","getNewsFeed","follow","postTweet","getNewsFeed","unfollow","getNewsFeed"]
args = [[],[1,5],[1],[1,2],[2,6],[1],[1,2],[1]]
[null,null,[5],null,null,[6,5],null,[5]]

From slow to fast

Approaches

1

Per-user lists + heap merge

Time O(f + 10 log f) per feed for f followees Space O(users + tweets + follows)

tweets: user → list of {time, id}. Feed: push each relevant user's latest tweet into a max-heap by time; pop up to 10, pushing that user's previous tweet each time.

▶ Dry run: Merge piles with a max-heap on timepost(1, 5); feed(1); follow(1, 2); post(2, 6); feed(1); unfollow(1, 2); feed(1)

tweets {time, id}(map)

user 1: [{0, 5}]

follows(map)

empty

state(vars)

clock: 1

Step 1/5post(1, 5): user 1's list gets tweet 5 stamped with time 0. The clock moves to 1.

Approach 1
import java.util.*;

class Twitter {
    private int clock = 0;
    private final Map<Integer, List<int[]>> tweets = new HashMap<>();      // {time, tweetId}
    private final Map<Integer, Set<Integer>> follows = new HashMap<>();

    public Twitter() {}

    public void postTweet(int userId, int tweetId) {
        tweets.computeIfAbsent(userId, k -> new ArrayList<>()).add(new int[]{clock++, tweetId});
    }

    public List<Integer> getNewsFeed(int userId) {
        Set<Integer> users = new HashSet<>(follows.getOrDefault(userId, Set.of()));
        users.add(userId);
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> Integer.compare(b[0], a[0]));   // {time, user, index}
        for (int u : users) {
            List<int[]> list = tweets.get(u);
            if (list != null && !list.isEmpty()) pq.offer(new int[]{list.get(list.size() - 1)[0], u, list.size() - 1});
        }
        List<Integer> feed = new ArrayList<>();
        while (!pq.isEmpty() && feed.size() < 10) {
            int[] top = pq.poll();
            List<int[]> list = tweets.get(top[1]);
            feed.add(list.get(top[2])[1]);
            if (top[2] > 0) pq.offer(new int[]{list.get(top[2] - 1)[0], top[1], top[2] - 1});
        }
        return feed;
    }

    public void follow(int followerId, int followeeId) {
        if (followerId != followeeId) follows.computeIfAbsent(followerId, k -> new HashSet<>()).add(followeeId);
    }

    public void unfollow(int followerId, int followeeId) {
        Set<Integer> s = follows.get(followerId);
        if (s != null) s.remove(followeeId);
    }
}

Verdict: Pull-based feed; real systems often precompute (push) for most users.

Before you submit

Edge cases and common mistakes

Test these inputs

  • Following yourself
  • Unfollowing someone not followed
  • Fewer than 10 tweets

Mistakes people make

  • Collecting and sorting every tweet of every followee for each feed.

Interview

Follow-up questions

How do real feeds scale?

Connect the dots

Where this shows up in real systems