题目
设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近 10 条推文。
实现 Twitter 类:
Twitter() 初始化简易版推特对象
void postTweet(int userId, int tweetId) 根据给定的 tweetId 和 userId 创建一条新推文。每次调用次函数都会使用一个不同的 tweetId 。
List getNewsFeed(int userId) 检索当前用户新闻推送中最近 10 条推文的 ID 。新闻推送中的每一项都必须是由用户关注的人或者是用户自己发布的推文。推文必须 按照时间顺序由最近到最远排序 。
void follow(int followerId, int followeeId) ID 为 followerId 的用户开始关注 ID 为 followeeId 的用户。
void unfollow(int followerId, int followeeId) ID 为 followerId 的用户不再关注 ID 为 followeeId 的用户。
代码
class Twitter {
private static int timestamp = 0;//全局时间戳
private static class Tweet{//推文类
private int id;
private int time;
private Tweet next;//连接下一个Tweet
public Tweet(int id, int time){//传入推文内容(id)和发文时间
this.id=id;
this.time=time;
this.next=null;
}
}
private static class User{
private int id;
public Set<Integer> followed;//粉丝集合
public Tweet head;
public User(int userId){
followed=new HashSet<>();
this.id=userId;
this.head=null;
// 默认需要关注自己
follow(id);
}
public void follow(int userId){
followed.add(userId);
}
public void unfollw(int userId){
// 默认不能取关自己
if (userId!= this.id)
followed.remove(userId);
}
public void post(int tweetId){//发布推特
Tweet twt=new Tweet(tweetId,timestamp);
timestamp++;//越靠前推文 time 值越大,用于不同用户的推特优先级比较
twt.next=head;//将此篇推文放在最头
head=twt;
}
}
private HashMap<Integer,User> userMap= new HashMap<>();//我们需要一个映射将 userId 和 User 对象对应起来
public Twitter() {
}
public void postTweet(int userId, int tweetId) {//发布一条tweet
// 若 userId 不存在,则新建
if (!userMap.containsKey(userId))
userMap.put(userId,new User(userId));
User u = userMap.get(userId);
u.post(tweetId);//调用User.post,发布一篇推文
}
public void follow(int followerId, int followeeId) {//关注功能
// 若follower未存在.新建一个
if (!userMap.containsKey(followerId)){
User u = new User(followerId);
userMap.put(followerId,u);
}
// 若 followee 不存在,则新建
if (!userMap.containsKey(followeeId)){
User u = new User(followeeId);
userMap.put(followeeId,u);
}
userMap.get(followerId).follow(followeeId);//关注操作
}
/** follower 取关 followee,如果 Id 不存在则什么都不做 */
public void unfollow(int followerId, int followeeId) {
if (userMap.containsKey(followerId)){
User flwer = userMap.get(followerId);
flwer.unfollw(followeeId);//取关操作
}
}
/** 返回该 user 关注的人(包括他自己)最近的动态 id,
最多 10 条,而且这些动态必须按从新到旧的时间线顺序排列。*/
public List<Integer> getNewsFeed(int userId) {//利用优先级队列(堆)
ArrayList<Integer> res = new ArrayList<>();//建立List用于放答案
if (!userMap.containsKey(userId)) return res;//若不存在,返回空
// 获取关注列表的用户id
Set<Integer> users = userMap.get(userId).followed;
// 声名一个堆,自动通过 time 属性从大到小排序,容量为 users 的大小
PriorityQueue<Tweet> pq = new PriorityQueue<>(users.size(),(a,b)->(b.time-a.time));//比较器
// 先将所有users的推文链表头节点插入优先级队列
for (int id: users
) {
Tweet head = userMap.get(id).head;
if (head==null) continue;//若没有,则去下一个user
pq.add(head);
}
while (!pq.isEmpty()){
// 最多返回10条即可
if (res.size()==10) break;
// 弹出的是time最大的。也就是说最新发表的
Tweet twt = pq.poll();
res.add(twt.id);//添加进res
// 把下一篇Tweet插入进行排序,若没有了就不加入
if (twt.next!=null)
pq.add(twt.next);
}
return res;
}
}
要点
- 面向对象设计根据labuladong的教程,构造User和Tweet类,设置全局时间戳来记录关注着和推文优先级。
- 当返回10个关注列表的文章时,通过优先级队列(堆)来比较时间戳,选出时间最近的10条。