题目描述:
设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文。你的设计需要支持以下的几个功能:
postTweet(userId, tweetId): 创建一条新的推文
getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由此用户关注的人或者是用户自己发出的。推文必须按照时间顺序由最近的开始排序。
follow(followerId, followeeId): 关注一个用户
unfollow(followerId, followeeId): 取消关注一个用户
示例:
Twitter twitter = new Twitter();
// 用户1发送了一条新推文 (用户id = 1, 推文id = 5).
twitter.postTweet(1, 5);
// 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
twitter.getNewsFeed(1);
// 用户1关注了用户2.
twitter.follow(1, 2);
// 用户2发送了一个新推文 (推文id = 6).
twitter.postTweet(2, 6);
// 用户1的获取推文应当返回一个列表,其中包含两个推文,id分别为 -> [6, 5].
// 推文id6应当在推文id5之前,因为它是在5之后发送的.
twitter.getNewsFeed(1);
// 用户1取消关注了用户2.
twitter.unfollow(1, 2);
// 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
// 因为用户1已经不再关注用户2.
twitter.getNewsFeed(1);
方法1:
主要思路:解题汇总 (1)使用两个哈希进行存储相关元素,一个哈希用于存储账户和该账户的粉丝,另一个哈希用于存储每个账户发表的推文,并给该推文加上个时间标签,同时使用一个正数 time 来对每个推文增加唯一的时间标签;
(2)构造函数中,将时间变量初始化为0,后面每标识一个推文,增加1;
(3)postTweet函数中,将对应的推文存储到对应的账户中,并增加时间标签进行标识;
(4)follow函数用于增加账户的粉丝,注意这里避免自己是自己的粉丝的情形;
(5)unfollow用于去除关注,在关注关系中,若该关注关系存在,则去除该关系,为了能够快速判断关注关系的存在性,使用 unordered_map<int,unordered_set>数据结构;
(6) getNewsFeed从关注的账户中,使用优先队列,找出时间最大的10个推文;
class Twitter {
public:
unordered_map<int,unordered_set<int>> follower_followee;//存储账户之间的关注关系
unordered_map<int,vector<pair<int,int>>> follower_news;//存储每个账户发表的推文
int time;
/** Initialize your data structure here. */
Twitter() {
time=0;
}
/** Compose a new tweet. */
void postTweet(int userId, int tweetId) {
follower_news[userId].push_back({time,tweetId});//存储每个账户的推文
++time;//时间标签增加1
}
/** 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. */
vector<int> getNewsFeed(int userId) {
vector<int> res;//存储结果
//使用优先队列找出时间最大的10个推文
priority_queue<vector<int>,vector<vector<int>>,less<vector<int>>> q;
//当前账户内若有推文,则将推文最新的推文压入到优先队列中,压入的四个元素为时间,推文,推文索引,当前账户
if(follower_news[userId].size()>0)
q.push({follower_news[userId].back().first,follower_news[userId].back().second,(int)follower_news[userId].size()-1,userId});
//将当前账户的关注账号的各个最新的推文压入到优先队列中
for(auto& it:follower_followee[userId]){
if(follower_news[it].size()>0)//若当前账户内有推文,则压入
q.push({follower_news[it].back().first,follower_news[it].back().second,(int)follower_news[it].size()-1,it});
}
//终止条件之一,优先队列内的元素全部弹出了
while(!q.empty()){
//取出当前最新的推文
vector<int> cur=q.top();
q.pop();
res.push_back(cur[1]);//压入当前最新推文的id
//判断当前最新的推文对应的账号是否还有推文,有的话,将下一个推文压入到队列中
if(cur[2]!=0){
--cur[2];
q.push({follower_news[cur[3]][cur[2]].first,follower_news[cur[3]][cur[2]].second,cur[2],cur[3]});
}
if(res.size()==10){//终止循环条件2,最新的10条推文都找到了
break;
}
}
return res;
}
/** Follower follows a followee. If the operation is invalid, it should be a no-op. */
void follow(int followerId, int followeeId) {
if(followerId!=followeeId){//若两个账号不是同一个账号
follower_followee[followerId].insert(followeeId);
}
}
/** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
void unfollow(int followerId, int followeeId) {
//若当前账号的关注关系存在
if(follower_followee.count(followerId)&&follower_followee[followerId].count(followeeId)){
follower_followee[followerId].erase(followeeId);
}
}
};
/**
* Your Twitter object will be instantiated and called as such:
* Twitter* obj = new Twitter();
* obj->postTweet(userId,tweetId);
* vector<int> param_2 = obj->getNewsFeed(userId);
* obj->follow(followerId,followeeId);
* obj->unfollow(followerId,followeeId);
*/