355 Design Twitter
Implement a simple twitter. Support the following method:
postTweet(user_id, tweet_text)
. Post a tweet.getTimeline(user_id)
. Get the given user's most recently 10 tweets posted by himself, order by timestamp from most recent to least recent.getNewsFeed(user_id)
. Get the given user's most recently 10 tweets in his news feed (posted by his friends and himself). Order by timestamp from most recent to least recent.follow(from_user_id, to_user_id)
. from_user_id followed to_user_id.unfollow(from_user_id, to_user_id)
. from_user_id unfollowed to to_user_id.
Example
postTweet(1, "LintCode is Good!!!")
>> 1
getNewsFeed(1)
>> [1]
getTimeline(1)
>> [1]
follow(2, 1)
getNewsFeed(2)
>> [1]
unfollow(2, 1)
getNewsFeed(2)
>> []
/**
* Definition of Tweet:
* public class Tweet {
* public int id;
* public int user_id;
* public String text;
* public static Tweet create(int user_id, String tweet_text) {
* // This will create a new tweet object,
* // and auto fill id
* }
* }
*/
public class MiniTwitter {
// storge <uid, tweet> -- db table
HashMap<Integer, ArrayList<TweetWithTS>> userTweetTable;
// foller table <from, to>
HashMap<Integer, HashSet<Integer>> followers;
Long globalOrder;// maybe able to use id as timestamp instead of using global variable
public MiniTwitter() {
userTweetTable = new HashMap<>();
followers = new HashMap<>();
globalOrder = 0L;
}
// @param user_id an integer
// @param tweet a string
// return a tweet
public Tweet postTweet(int user_id, String tweet_text) {
// add tweet to usser - tweet table
ArrayList<TweetWithTS> tmp;
Tweet newTwt = Tweet.create(user_id, tweet_text);
TweetWithTS tweetWithTime = new TweetWithTS(newTwt, globalOrder++);
// check null every where
if (userTweetTable.containsKey(user_id)) {
tmp = userTweetTable.get(user_id);
} else {
tmp = new ArrayList<>();
}
// tmp is reference, will add to actual list in hashmap
tmp.add(tweetWithTime);
userTweetTable.put(user_id, tmp);
return newTwt;
}
// @param user_id an integer
// return a list of 10 new feeds recently
// and sort by timeline
// -------use pull----------
public List<Tweet> getNewsFeed(int user_id) {
// get all user this user followed
HashSet<Integer> followTarget;
// check null every whare
if (followers.containsKey(user_id)) {
followTarget = followers.get(user_id);
} else {
followTarget = new HashSet<>();
}
followTarget.add(user_id);// this will add user to his/her follow target list, which won't affect anything here, we may want to avoid this ?
// extract last 10 tweets from each of follow targets
// min heap when we need last 10 (recent tweets has TimeStamp later ->
// bigger)
TreeSet<TweetWithTS> treeSet = new TreeSet<>(new Comparator<TweetWithTS>() {
public int compare(TweetWithTS t1, TweetWithTS t2) {
return t1.ts.compareTo(t2.ts);
}
});
for (Integer fid : followTarget) {
List<TweetWithTS> cur = userTweetTable.get(fid);
if (cur == null) {
continue;
}
int size = cur.size();
int from = size - 10 > 0 ? size - 10 : 0;
cur = cur.subList(from, size);
treeSet.addAll(cur);
}
// get last 10 out of the set
ArrayList<Tweet> res = new ArrayList<>();
for (int i = 0; i < 10 && !treeSet.isEmpty(); i++) {
res.add(treeSet.pollLast().tw);
}
return res;
}
// @param user_id an integer
// return a list of 10 new posts recently
// and sort by timeline
public List<Tweet> getTimeline(int user_id) {
List<TweetWithTS> tmp = new ArrayList<>();// we new a list here so we won't change the actual list in hashmap
List<Tweet> res = new ArrayList<>();
if (userTweetTable.containsKey(user_id)) {
tmp.addAll(userTweetTable.get(user_id));
// here we need to use reverse order, if you use ascending order and get last 10, you will still need to reverse them when you return
Collections.sort(tmp, new Comparator<TweetWithTS>() {
@Override
public int compare(TweetWithTS t1, TweetWithTS t2) {
return t2.ts.compareTo(t1.ts);
}
});
// remember only return 10
int size = tmp.size();
int to = size - 10 > 0 ? 10 : size;
tmp = tmp.subList(0, to);
res = extractTweets(tmp);
}
return res;
}
// @param from_user_id an integer
// @param to_user_id an integer
// from user_id follows to_user_id
public void follow(int from_user_id, int to_user_id) {
HashSet<Integer> tmp;
// check null every whare
if (followers.containsKey(from_user_id)) {
tmp = followers.get(from_user_id);
} else {
tmp = new HashSet<>();
}
tmp.add(to_user_id);
followers.put(from_user_id, tmp);
}
// @param from_user_id an integer
// @param to_user_id an integer
// from user_id unfollows to_user_id
public void unfollow(int from_user_id, int to_user_id) {
HashSet<Integer> tmp = followers.get(from_user_id);
if (tmp != null) {
tmp.remove(to_user_id);
followers.put(from_user_id, tmp);
}
}
// this method is to extract tweets from tweetsWithTimeStamp
private List<Tweet> extractTweets(List<TweetWithTS> list) {
ArrayList<Tweet> res = new ArrayList<>();
for (TweetWithTS t : list) {
res.add(t.tw);
}
return res;
}
}
class TweetWithTS {
Long ts;
Tweet tw;
public TweetWithTS(Tweet tweet, Long ts) {
this.ts = ts;
this.tw = tweet;
}
}
Last updated