/* * 355. Design Twitter * 2016-7-13 by Mingyang * 系统设计真的被玩坏了 */ class Twitter { private static int timeStamp=0; // easy to find if user exist private Map<Integer, User> userMap; // Tweet link to next Tweet so that we can save a lot of time // when we execute getNewsFeed(userId) private class Tweet{ public int id; public int time; public Tweet next; public Tweet(int id){ this.id = id; time = timeStamp++; next=null; } } // OO design so User can follow, unfollow and post itself public class User{ public int id; public Set<Integer> followed; public Tweet tweet_head; public User(int id){ this.id=id; followed = new HashSet<>(); follow(id); // first follow itself tweet_head = null; } public void follow(int id){ followed.add(id); } public void unfollow(int id){ followed.remove(id); } // everytime user post a new tweet, add it to the head of tweet list. public void post(int id){ Tweet t = new Tweet(id); t.next=tweet_head; tweet_head=t; } } /** Initialize your data structure here. */ public Twitter() { userMap = new HashMap<Integer, User>(); } /** Compose a new tweet. */ public void postTweet(int userId, int tweetId) { if(!userMap.containsKey(userId)){ User u = new User(userId); userMap.put(userId, u); } userMap.get(userId).post(tweetId); } // Best part of this. // first get all tweets lists from one user including itself and all people it followed. // Second add all heads into a max heap. Every time we poll a tweet with // largest time stamp from the heap, then we add its next tweet into the heap. // So after adding all heads we only need to add 9 tweets at most into this // heap before we get the 10 most recent tweet. public List<Integer> getNewsFeed(int userId) { List<Integer> res = new LinkedList<>(); if(!userMap.containsKey(userId)) return res; Set<Integer> users = userMap.get(userId).followed; PriorityQueue<Tweet> q = new PriorityQueue<Tweet>(users.size(), new Comparator<Tweet>() { @Override public int compare(Tweet i1, Tweet i2) { return i2.time - i1.time; } }); //(a,b)->(b.time-a.time)); for(int user: users){ Tweet t = userMap.get(user).tweet_head; // very imporant! If we add null to the head we are screwed. if(t!=null){ q.add(t); } } int n=0; while(!q.isEmpty() && n<10){ Tweet t = q.poll(); res.add(t.id); n++; if(t.next!=null) q.add(t.next); } return res; } /** Follower follows a followee. If the operation is invalid, it should be a no-op. */ public void follow(int followerId, int followeeId) { if(!userMap.containsKey(followerId)){ User u = new User(followerId); userMap.put(followerId, u); } if(!userMap.containsKey(followeeId)){ User u = new User(followeeId); userMap.put(followeeId, u); } userMap.get(followerId).follow(followeeId); } /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */ public void unfollow(int followerId, int followeeId) { if(!userMap.containsKey(followerId) || followerId==followeeId) return; userMap.get(followerId).unfollow(followeeId); } }