Monday, July 4, 2016

355. Design Twitter

We need to use hash map to store the mapping between one follower and followees. Each follower has multiple followees so we need set to store all followees for one follower. For tweets, we need to add timeline for each tweet such that we know which is the latest one. When popping out top latest 10 tweets of a user, all we need to do is:
(1). Get all friends of this user.
(2). Iterate the friend list.
(3). For each friend, iterate his/her tweets list.
(4). We use a priority queue with least recent tweets on top to keep the 10 most recent tweets. If the queue is not full, we keep pushing. If the queue is full, we check the top tweet is less recent than the incoming tweet. If so, push the incoming tweet into the queue. If not, we stop scanning this friend's tweets because his/her tweets are ordered from most recent to least recent. If the queue size is large than 10, we pop out the top.
(5). At the end, we output tweets in the queue in reverse order.

Also, one important point that can be easy to miss is that user herself need to follow herself! Why? Because she must be able to see her own tweets. Also when doing unfollow, we need to make sure that user mustn't unfollow herself.

Note, line 14 is an optimization for getNewsFeed(), so that line 22 can detect early break.

1:  class Twitter {  
2:  private:  
3:    unordered_map<int, unordered_set<int>> friends;  
4:    unordered_map<int, vector<pair<int, int>>> tweets;  
5:    int time;  
6:  public:  
7:    /** Initialize your data structure here. */  
8:    Twitter() {  
9:      time = 0;  
10:    }  
11:    /** Compose a new tweet. */  
12:    void postTweet(int userId, int tweetId) {  
13:      follow(userId, userId);  
14:      tweets[userId].insert(tweets[userId].begin(), pair<int, int>(++time, tweetId));  
15:    }  
16:    /** Retrieve the 10 most recent tweet ids in the user's news feed. 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. */  
17:    vector<int> getNewsFeed(int userId) {  
18:      vector<int> res;  
19:      priority_queue<pair<int, int>, vector<pair<int, int>>, std::greater<pair<int, int>>> que;  
20:      for (int f : friends[userId]) {  
21:        for (pair<int, int> t : tweets[f]) {  
22:          if (que.size() == 10 && que.top().first > t.first) break;  
23:          que.push(t);  
24:          if (que.size() > 10) que.pop();  
25:        }  
26:      }  
27:      while (!que.empty()) {  
28:        res.push_back(que.top().second);  
29:        que.pop();  
30:      }  
31:      reverse(res.begin(), res.end());  
32:      return res;  
33:    }  
34:    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */  
35:    void follow(int followerId, int followeeId) {  
36:      friends[followerId].insert(followeeId);  
37:    }  
38:    /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */  
39:    void unfollow(int followerId, int followeeId) {  
40:      if (followerId != followeeId) {  
41:        friends[followerId].erase(followeeId);  
42:      }  
43:    }  
44:  };  
45:  /**  
46:   * Your Twitter object will be instantiated and called as such:  
47:   * Twitter obj = new Twitter();  
48:   * obj.postTweet(userId,tweetId);  
49:   * vector<int> param_2 = obj.getNewsFeed(userId);  
50:   * obj.follow(followerId,followeeId);  
51:   * obj.unfollow(followerId,followeeId);  
52:   */  

No comments:

Post a Comment