创建两个HashMap,一个存user,一个存tweets。以及整型的时间戳timestamp。user
的k-v pair是userId-follower_set,tweets
的k-v pair是userId-tweets_linkedlist,tweets属于Tweet类,包含time和id两个参数。node
postTweet(userId, tweetId):
首先,对于发推的主体,user,要存放在userMap中,并且user要follow本身,因此,userMap.get(userId).add(userId);
而后,在tweets中找到key值userId,将该用户全部推特内容放入值域的哈希表中。数组
getNewsFeed(userId):
首先创建按时间戳从大到小排列的PriorityQueue,找到userMap中的userId,filter出其中在tweet中存在的follower,把每个follower的推特链表放入PriorityQueue,再从PriorityQueue中取头十条推特的id放入结果数组。数据结构
follow(followerId, followeeId):
将followeeId加入userMap中的followerId键值。函数
unfollow(followId, followeeId):
将followeeId从userMap中的followerId键值里删除。post
public class Twitter { Map<Integer, Set<Integer>> userMap = new HashMap<>(); Map<Integer, LinkedList<Tweet>> tweets = new HashMap<>(); int timestamp = 0; class Tweet { int time; int id; Tweet(int time, int id) { this.time = time; this.id = id; } } public void postTweet(int userId, int tweetId) { if (!userMap.containsKey(userId)) userMap.put(userId, new HashSet<>()); userMap.get(userId).add(userId); if (!tweets.containsKey(userId)) tweets.put(userId, new LinkedList<>()); tweets.get(userId).addFirst(new Tweet(timestamp++, tweetId)); } public List<Integer> getNewsFeed(int userId) { if (!userMap.containsKey(userId)) return new LinkedList<>(); PriorityQueue<Tweet> feed = new PriorityQueue<>((t1, t2) -> t2.time-t1.time); userMap.get(userId).stream().filter(f -> tweets.containsKey(f)) .forEach(f -> tweets.get(f).forEach(feed::add)); List<Integer> res = new LinkedList<>(); while (feed.size() > 0 && res.size() < 10) res.add(feed.poll().id); return res; } public void follow(int followerId, int followeeId) { if (!userMap.containsKey(followerId)) userMap.put(followerId, new HashSet<>()); userMap.get(followerId).add(followeeId); } public void unfollow(int followerId, int followeeId) { if (userMap.containsKey(followerId) && followeeId != followerId) userMap.get(followerId).remove(followeeId); } }
Implement a simple twitter. Support the following method:this
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.设计
postTweet(1, "LintCode is Good!!!") -->> 1 getNewsFeed(1) -->> [1] getTimeline(1) -->> [1] follow(2, 1) getNewsFeed(2) -->> [1] unfollow(2, 1) getNewsFeed(2) -->> []
设计一个mini Twitter,刚放出来的几道系统设计题里,这道题才算是关于设计的题目。
要实现这么五个功能:code
发推:须要用户ID,推特内容,该推特的时间戳; 时间线:须要用户ID,该用户的推特集,每条推特的时间戳,比较器; 新鲜事:须要用户ID,好友ID集合,选定用户群(用户ID和全部好友ID)的推特集(选定用户的推特集,时间戳),比较器; 关注:须要用户ID,被关注用户ID,好友ID集合; 取关:须要用户ID,被关注用户ID,好友ID集合;
以上,根据功能的要求,肯定相关变量。而后选择适当的数据结构:对象
已经给出的:Tweet(user_id, text, id, create()),
没有给出可是须要的:时间戳order,带时间戳的推特Node,推特集,全部推特集users_tweets,好友集friends,整个系统MiniTwitter,排序
而后,分析一下具体对象之间的逻辑关系:
Node: 包含Tweet
和order
,构造Node
类;
users_tweets: 包含user_id
,和对应id的推特集List<Node>
,使用Map<Integer, List<Node>>
的数据结构;
friends: 包含user_id
,每一个id对应一个好友集Map<Integer, Boolean>
(即Map<user-id, isFriend>()
),使用Map<Integer, Map<Integer, Boolean>>
的数据结构。
这样就很清楚了,咱们须要创建一个包含Tweet
和Order
的Node
类,同时声明两个全局变量users_tweets
和friends
。
而后考虑要求实现的功能。
发推,要用给出的Tweet.create(user_id, tweet_text)
函数,而后将集成Tweet和order的Node
和对应的user_id
放入users_tweets
;
时间线,须要从users_tweets
中按照Order
取出对应user_id
的后10
个Node
,再取出Node.tweet
放入结果数组List<Tweet>
,注意tweet
的大小写;
新鲜事,须要查看user_id
的好友列表,将包括本身的每一个人的后10
个Node
放入List<Node> temp
,再对temp
中全部Node
进行排序,取出前10
个Node
。这里发现order
不是对应于单个user_id
的,而是对应users_tweets
中的全部Node
。
因此,order
也要声明为全局变量。
继续,关注好友,添加或查找from_user_id
做为friends
中的key值,而后对这个key值对应的value,也就是Map<Integer, Boolean>
,添加to_user_id
和true
的pair。
取关好友,和关注好友相同的操做,先从friend
中get
的from_user_id
的key值,再remove
对应Map中to_user_id
的pair便可。
下面讨论以上功能实现须要增长的细节。首先,取出前十个Node
,取出后十个Node
,须要创建两个函数getFirstTen()
和getLastTen()
,对List<Node> temp
进行操做。因为取出子数组的顺序依然相对不变,temp.subList(start, end)
返回的十个Node
须要被从大到小排序,以知足most recent的要求(order
从大到小),咱们须要构造新的Comparator SortByOrder
,对Node
类型的数组排序。注意在Comparator
的实现上,return 1
表明须要交换,return -1
表明不须要交换。
最后,在功能函数的前面,进行MiniTweeter()
的初始化。
结束~
public class MiniTwitter { class Node { public int order; public Tweet tweet; public Node(int order, Tweet tweet) { this.order = order; this.tweet = tweet; } } class SortByOrder implements Comparator { public int compare(Object obj1,Object obj2) { Node node1 = (Node) obj1; Node node2 = (Node) obj2; if (node1.order < node2.order) return 1; else return -1; } } private Map<Integer, Map<Integer, Boolean>> friends; private Map<Integer, List<Node>> users_tweets; private int order; public List<Node> getLastTen(List<Node> temp) { int last = 10; if (temp.size() < 10) last = temp.size(); return temp.subList(temp.size() - last, temp.size()); } public List<Node> getFirstTen(List<Node> temp) { int last = 10; if (temp.size() < 10) last = temp.size(); return temp.subList(0, last); } public MiniTwitter() { // initialize your data structure here. this.friends = new HashMap<Integer, Map<Integer, Boolean>>(); this.users_tweets = new HashMap<Integer, List<Node>>(); this.order = 0; } // @param user_id an integer // @param tweet a string // return a tweet public Tweet postTweet(int user_id, String text) { Tweet tweet = Tweet.create(user_id, text); if (!users_tweets.containsKey(user_id)) users_tweets.put(user_id, new ArrayList<Node>()); order += 1; users_tweets.get(user_id).add(new Node(order, tweet)); return tweet; } // @param user_id an integer // return a list of 10 new feeds recently // and sort by timeline public List<Tweet> getNewsFeed(int user_id) { List<Node> temp = new ArrayList<Node>(); if (users_tweets.containsKey(user_id)) temp.addAll(getLastTen(users_tweets.get(user_id))); if (friends.containsKey(user_id)) { for (Map.Entry<Integer, Boolean> entry : friends.get(user_id).entrySet()) { int user = entry.getKey(); if (users_tweets.containsKey(user)) temp.addAll(getLastTen(users_tweets.get(user))); } } Collections.sort(temp, new SortByOrder()); List<Tweet> res = new ArrayList<Tweet>(); temp = getFirstTen(temp); for (Node node : temp) { res.add(node.tweet); } 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<Node> temp = new ArrayList<Node>(); if (users_tweets.containsKey(user_id)) temp.addAll(getLastTen(users_tweets.get(user_id))); Collections.sort(temp, new SortByOrder()); List<Tweet> res = new ArrayList<Tweet>(); temp = getFirstTen(temp); for (Node node : temp) res.add(node.tweet); 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) { if (!friends.containsKey(from_user_id)) friends.put(from_user_id, new HashMap<Integer, Boolean>()); friends.get(from_user_id).put(to_user_id, true); } // @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) { if (friends.containsKey(from_user_id)) friends.get(from_user_id).remove(to_user_id); } }