Open In App

Design custom Twitter based on given operations

Last Updated : 24 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Design a simplified version of Twitter where users can post tweets, follow/unfollow another user, and see the 10 most recent tweets in their news feed. 

Our design should support the following methods:

  • postTweet (userId, tweetId): Compose a new tweet.
  • getNewsFeed (userId): Retrieve the 10 most recent tweet ids in the user’s news feed. (If the total number of tweets in the news feed is less than 10, then return all.) Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent.
  • follow (followerId, followeeId): Follower follows a followee.
  • unfollow (followerId, followeeId): Follower unfollows a followeSe. 

The task is to design a data structure that supports the above mentioned functionalities.

Examples:

Input:
postTweet(1, 5);
getNewsFeed(1);
follow(1, 2);
postTweet(2, 6);
getNewsFeed(1);
unfollow(1, 2);
getNewsFeed(1);
Output:
[5]
[6, 5]
[5]
Explanation: 
postTweet(1, 5): User1 posts a new tweet having a tweetId=5 
getNewsFeed(1): returns a list with 1 tweet having tweetId=5
follow(1, 2): User 1 follows user 2.
postTweet(2, 6): User 2 posts a new tweet having a tweetId=6 
getNewsFeed(1): returns a list with 2 tweets [6, 5]. One tweet belongs to him and the other one followee’s tweet. The tweets are sorted from most recent to least. 
unfollow(1, 2): User 1 unfollows user 2
getNewsFeed(1): returns a list with 1 tweet [5] since user 1 unfollowed user 2 and is no longer following anyone.

Input:
follow(1, 2);
postTweet(1, 3);
getNewsFeed(2);
Output: []
Explanation:
follow(1, 2): User 1 follows user 2.
postTweet(1, 3): User1 posts a new tweet having a tweetId=3
getNewsFeed(2): returns a list with 0 tweet [], because user2 have no tweets and doesn’t follow anyone. 

Approach: Implement the idea below to solve the problem:

We can implement the functionalities by using a map of sets and a priority queue of vectors. The map will help in keeping the record about a user and the ones he/she is following and the priority queue will help in keeping record about the timeline of tweets.

Follow the steps mentioned below to implement the idea

  • Maintain a user manual to keep track of the user and his friends or the ones he follows by implementing a map of sets i.e., (map<int, set<int>> friends_of_User)
  • Use a priority queue of vectors to maintain a timeline of the tweets to fetch the most recent tweets i.e., (priority_queue<vector<int>> timeline). 
  • Push the tweets in this timeline by maintaining their priority i.e., the most recent tweet will have more priority.
  • Create a userTimeline for a particular user. 
  • Now check if the tweet has been posted by the user or one of its friends and return the most recent tweets.
  • If the user wishes to follow another user, add that person’s id corresponding to the followerId in the map of sets.
  • If the user wishes to unfollow another user, remove that person’s id corresponding to the followerId from the map. 

Below is the implementation of the above approach. 

C++




// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
 
class Twitter {
public:
    // Maintaining the list of friends the user has.
    map<int, set<int> > friends_of_User;
    int curr = 0;
 
    // To store the tweets sorted as most recent
    priority_queue<vector<int> > timeline;
 
    Twitter()
    {
        friends_of_User.clear();
        curr = 0;
        timeline = priority_queue<vector<int> >();
    }
 
    // Function to add tweet in timeline for
    // the particular user
    void postTweet(int userId, int tweetId)
    {
        timeline.push({ curr++, tweetId, userId });
    }
 
    // Function to get top recent 10 tweets
    vector<int> getNewsFeed(int userId)
    {
        vector<int> ans;
        priority_queue<vector<int> > userTimeline
            = timeline;
        int n = 0;
 
        while (!userTimeline.empty() && n < 10) {
            auto topTweet = userTimeline.top();
            userTimeline.pop();
 
            // Check whether the tweet has been
            // posted by the user or one of the friends
            if (topTweet[2] == userId
                || friends_of_User[userId].count(
                       topTweet[2])) {
                ans.push_back(topTweet[1]);
                n++;
            }
        }
        return ans;
    }
 
    void follow(int followerId, int followeeId)
    {
        // Insert the followeeId in the map
        // corresponding to the followerId
        friends_of_User[followerId].insert(followeeId);
    }
 
    void unfollow(int followerId, int followeeId)
    {
        // Remove the followeeId in the map
        // corresponding to the followerId
        friends_of_User[followerId].erase(followeeId);
    }
};
 
// Driver code
int main()
{
    Twitter obj;
    int userId, tweetId;
 
    // Post tweet
    userId = 1, tweetId = 5;
    obj.postTweet(userId, tweetId);
 
    // Get newsfeed
    vector<int> vec = obj.getNewsFeed(userId);
    for (int a : vec)
        cout << a << " ";
    cout << endl;
 
    // Follow
    int follower, followee;
    follower = 1, followee = 2;
    obj.follow(follower, followee);
 
    // Post Tweet
    userId = 2, tweetId = 6;
    obj.postTweet(userId, tweetId);
 
    // Get newsfeed
    userId = 1;
    vec = obj.getNewsFeed(userId);
    for (int a : vec)
        cout << a << " ";
    cout << endl;
 
    // Unfollow
    follower = 1, followee = 2;
    obj.unfollow(follower, followee);
 
    // Get newsfeed
    vec = obj.getNewsFeed(userId);
    for (int a : vec)
        cout << a << " ";
    cout << endl;
 
    return 0;
}


Java




// Java code to implement the approach
 
import java.io.*;
import java.util.*;
 
class Twitter {
    // Maintaining the list of friends the user has.
    Map<Integer, Set<Integer> > friendsOfUser;
    int curr = 0;
 
    // To store the tweets sorted as most recent
    PriorityQueue<int[]> timeline;
 
    public Twitter()
    {
        friendsOfUser = new HashMap<>();
        curr = 0;
        timeline
            = new PriorityQueue<>((a, b) -> b[0] - a[0]);
    }
 
    // Function to add tweet in timeline for
    // the particular user
    void postTweet(int userId, int tweetId)
    {
        timeline.add(new int[] { curr++, tweetId, userId });
    }
 
    // Function to get top recent 10 tweets
    List<Integer> getNewsFeed(int userId)
    {
        List<Integer> ans = new ArrayList<>();
        PriorityQueue<int[]> userTimeline
            = new PriorityQueue<>(timeline);
        int n = 0;
 
        while (!userTimeline.isEmpty() && n < 10) {
            int[] topTweet = userTimeline.poll();
 
            // Check whether the tweet has been
            // posted by the user or one of the friends
            if (topTweet[2] == userId
                || (friendsOfUser.containsKey(userId)
                    && friendsOfUser.get(userId).contains(
                        topTweet[2]))) {
                ans.add(topTweet[1]);
                n++;
            }
        }
        return ans;
    }
 
    void follow(int followerId, int followeeId)
    {
        // Insert the followeeId in the map
        // corresponding to the followerId
        if (!friendsOfUser.containsKey(followerId)) {
            friendsOfUser.put(followerId, new HashSet<>());
        }
        friendsOfUser.get(followerId).add(followeeId);
    }
 
    void unfollow(int followerId, int followeeId)
    {
        // Remove the followeeId in the map
        // corresponding to the followerId
        if (friendsOfUser.containsKey(followerId)) {
            friendsOfUser.get(followerId)
                .remove(followeeId);
        }
    }
}
 
class GFG {
    public static void main(String[] args)
    {
        Twitter obj = new Twitter();
        int userId, tweetId;
 
        // Post tweet
        userId = 1;
        tweetId = 5;
        obj.postTweet(userId, tweetId);
 
        // Get newsfeed
        List<Integer> vec = obj.getNewsFeed(userId);
        for (Integer a : vec) {
            System.out.print(a + " ");
        }
        System.out.println();
 
        // Follow
        int follower, followee;
        follower = 1;
        followee = 2;
        obj.follow(follower, followee);
 
        // Post Tweet
        userId = 2;
        tweetId = 6;
        obj.postTweet(userId, tweetId);
 
        // Get newsfeed
        userId = 1;
        vec = obj.getNewsFeed(userId);
        for (Integer a : vec) {
            System.out.print(a + " ");
        }
        System.out.println();
 
        // Unfollow
        follower = 1;
        followee = 2;
        obj.unfollow(follower, followee);
 
        // Get newsfed
        vec = obj.getNewsFeed(userId);
        for (Integer a : vec) {
            System.out.print(a + " ");
        }
        System.out.println();
    }
}
 
// This code is contributed by lokeshmvs21.


Python3




# Python code to implement the approach
 
import heapq
 
 
class Twitter:
    def __init__(self):
         # Maintaining the list of friends the user has.
        self.friends_of_User = {}
        self.curr = 0
        # To store the tweets sorted as most recent
        self.timeline = []
 
        # Function to add tweet in timeline for
       # the particular user
    def postTweet(self, userId, tweetId):
        heapq.heappush(self.timeline, [-self.curr, tweetId, userId])
        self.curr += 1
 
    # Function to get top recent 10 tweets
    def getNewsFeed(self, userId):
        ans = []
        userTimeline = self.timeline[:]
        n = 0
 
        while userTimeline and n < 10:
            topTweet = heapq.heappop(userTimeline)
 
            # Check whether the tweet has been
            # posted by the user or one of the friends
            if topTweet[2] == userId or userId in self.friends_of_User and topTweet[2] in self.friends_of_User[userId]:
                ans.append(topTweet[1])
                n += 1
 
        return ans
 
    def follow(self, followerId, followeeId):
        # Insert the followeeId in the map
        # corresponding to the followerId
        if followerId not in self.friends_of_User:
            self.friends_of_User[followerId] = set()
        self.friends_of_User[followerId].add(followeeId)
 
    def unfollow(self, followerId, followeeId):
         # Remove the followeeId in the map
        # corresponding to the followerId
 
        if followerId in self.friends_of_User and followeeId in self.friends_of_User[followerId]:
            self.friends_of_User[followerId].remove(followeeId)
 
 
# Driver code
if __name__ == '__main__':
    obj = Twitter()
    userId, tweetId = 1, 5
 
    # Post tweet
    obj.postTweet(userId, tweetId)
 
    # Get newsfeed
    vec = obj.getNewsFeed(userId)
    for a in vec:
        print(a, end=' ')
    print()
 
    # Follow
    follower, followee = 1, 2
    obj.follow(follower, followee)
 
    # Post tweet
    userId, tweetId = 2, 6
    obj.postTweet(userId, tweetId)
 
    # Get newsfeed
    userId = 1
    vec = obj.getNewsFeed(userId)
    for a in vec:
        print(a, end=' ')
    print()
 
    # Unfollow
    follower, followee = 1, 2
    obj.unfollow(follower, followee)
 
    # Get newsfeed
    vec = obj.getNewsFeed(userId)
    for a in vec:
        print(a, end=' ')
    print()


C#




using System;
using System.Collections.Generic;
 
public class Twitter {
    // Maintaining the list of friends the user has.
    public Dictionary<int, HashSet<int> > friendsOfUser;
    public int curr;
    // To store the tweets sorted as most recent
    public List<Tuple<int, int, int> > timeline;
 
    public Twitter()
    {
        friendsOfUser
            = new Dictionary<int, HashSet<int> >();
        curr = 0;
        timeline = new List<Tuple<int, int, int> >();
    }
 
    // Function to add tweet in timeline for the particular
    // user
    public void postTweet(int userId, int tweetId)
    {
        timeline.Add(new Tuple<int, int, int>(
            -curr, tweetId, userId));
        curr++;
    }
 
    // Function to get top recent 10 tweets
    public List<int> getNewsFeed(int userId)
    {
        List<int> ans = new List<int>();
        List<Tuple<int, int, int> > userTimeline
            = new List<Tuple<int, int, int> >(timeline);
        userTimeline.Sort();
        int n = 0;
 
        foreach(var topTweet in userTimeline)
        {
            if (n >= 10)
                break;
 
            // Check whether the tweet has been posted by
            // the user or one of the friends
            if (topTweet.Item3 == userId
                || friendsOfUser.ContainsKey(userId)
                       && friendsOfUser[userId].Contains(
                           topTweet.Item3)) {
                ans.Add(topTweet.Item2);
                n++;
            }
        }
 
        return ans;
    }
 
    public void follow(int followerId, int followeeId)
    {
        // Insert the followeeId in the map corresponding to
        // the followerId
        if (!friendsOfUser.ContainsKey(followerId))
            friendsOfUser[followerId] = new HashSet<int>();
        friendsOfUser[followerId].Add(followeeId);
    }
 
    public void unfollow(int followerId, int followeeId)
    {
        // Remove the followeeId in the map corresponding to
        // the followerId
        if (friendsOfUser.ContainsKey(followerId))
            friendsOfUser[followerId].Remove(followeeId);
    }
}
 
// Driver code
public class Program {
    static void Main()
    {
        Twitter obj = new Twitter();
        int userId = 1;
        int tweetId = 5;
 
        // Post tweet
        obj.postTweet(userId, tweetId);
 
        // Get newsfeed
        List<int> vec = obj.getNewsFeed(userId);
        foreach(int a in vec) Console.Write(a + " ");
        Console.WriteLine();
 
        // Follow
        int follower = 1;
        int followee = 2;
        obj.follow(follower, followee);
 
        // Post Tweet
        userId = 2;
        tweetId = 6;
        obj.postTweet(userId, tweetId);
 
        // Get newsfeed
        userId = 1;
        vec = obj.getNewsFeed(userId);
        foreach(int a in vec) { Console.Write(a + " "); }
        Console.WriteLine();
 
        // Unfollow
        follower = 1;
        followee = 2;
        obj.unfollow(follower, followee);
 
        // Get newsfed
          Console.Write(vec[1]);
        Console.WriteLine();
    }
}


Javascript




//JavaScript code to implement the approach
class Twitter {
  constructor() {
    // Maintaining the list of friends the user has.
    this.friends_of_User = {};
    this.curr = 0;
    // To store the tweets sorted as most recent
    this.timeline = [];
  }
 
  // Function to add tweet in timeline for
  // the particular user
  postTweet(userId, tweetId) {
    this.timeline.push([-this.curr, tweetId, userId]);
    this.curr += 1;
    this.heapify();
  }
 
  // Function to get top recent 10 tweets
  getNewsFeed(userId) {
    const ans = [];
    const userTimeline = [...this.timeline];
    let n = 0;
 
    while (userTimeline.length && n < 10) {
      const topTweet = userTimeline.shift();
 
      // Check whether the tweet has been
      // posted by the user or one of the friends
      if (topTweet[2] === userId || (userId in this.friends_of_User && this.friends_of_User[userId].has(topTweet[2]))) {
        ans.push(topTweet[1]);
        n += 1;
      }
    }
 
    return ans;
  }
 
  follow(followerId, followeeId) {
    // Insert the followeeId in the set
    // corresponding to the followerId
    if (!(followerId in this.friends_of_User)) {
      this.friends_of_User[followerId] = new Set();
    }
    this.friends_of_User[followerId].add(followeeId);
  }
 
  unfollow(followerId, followeeId) {
    // Remove the followeeId from the set
    // corresponding to the followerId
    if (followerId in this.friends_of_User && this.friends_of_User[followerId].has(followeeId)) {
      this.friends_of_User[followerId].delete(followeeId);
    }
  }
 
  // Helper function to heapify the timeline
  heapify() {
    let i = this.timeline.length - 1;
    while (i > 0) {
      const j = Math.floor((i - 1) / 2);
      if (this.timeline[j][0] < this.timeline[i][0]) {
        break;
      }
      const temp = this.timeline[i];
      this.timeline[i] = this.timeline[j];
      this.timeline[j] = temp;
      i = j;
    }
  }
}
 
// Driver code
const obj = new Twitter();
let userId = 1,
  tweetId = 5;
 
// Post tweet
obj.postTweet(userId, tweetId);
 
// Get newsfeed
let vec = obj.getNewsFeed(userId);
console.log(vec.join(" "));
 
// Follow
let follower = 1,
  followee = 2;
obj.follow(follower, followee);
 
// Post tweet
userId = 2;
tweetId = 6;
obj.postTweet(userId, tweetId);
 
// Get newsfeed
userId = 1;
vec = obj.getNewsFeed(userId);
console.log(vec.join(" "));
 
// Unfollow
follower = 1;
followee = 2;
obj.unfollow(follower, followee);
 
// Get newsfeed
vec = obj.getNewsFeed(userId);
console.log(vec.join(" "));


Output

5 
6 5 
5 

Time complexity: 

  • postTweet (userId, tweetId): O(logN)
  • getNewsFeed (userId): O(N * logN) 
  • follow (followerId, followeeId) and unfollow (followerId, followeeId): O(logN)
  • All the above complexities are for a single query.

Auxiliary Space: O(N)

Related Articles:



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads