355. 设计推特
难度中等72收藏分享切换为英文关注反馈
设计一个简化版的推特(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);
#include"pch.h"
#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_set>
#include<unordered_map>
using namespace std;
/*对于每一个用户,需要存储他关注的用户id、发的推文的id,
用户id不一定连续,所以需要一个以用户id为索引的哈希表存储用户信息。
1.postTweet(userId, tweetId): 创建一条新的推文
2.getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由此用户关注的人或者是用户自己发出的。
推文必须按照时间顺序由最近的开始排序。
3.follow(followerId, followeeId): 关注一个用户
4.unfollow(followerId, followeeId): 取消关注一个用户
对于3、4,需要一个hash表存储,插入和删除的时间复杂度都为O(1)
由于2需要知道关注的人和自己发出的最近的10条推文,所以可以考虑对每个用户用链表存储发送的推文,
每次创建推文的时候,在链表头插入,从而保证链表中时间从近到久。
那么对于2,就是需要合并若干条有序链表,找到合起来最近的10条推文,由于链表中数据有序,所以线性合并。
对于1,当发现链表节点数为resentMax时,删除链表末尾的元素,再插入最新的推文。
执行用时 :92 ms, 在所有 C++ 提交中击败了28.35%的用户
内存消耗 :21.5 MB, 在所有 C++ 提交中击败了66.67%的用户*/
class Twitter {
struct Node {
unordered_set<int> followee;//hash表存储关注的用户id
list<int> tweet;//链表存储推文id
};
int resentMax, time;
unordered_map<int, int> tweetTime;//推文发送的时间
unordered_map<int, Node> user;//用户id对应的结构
public:
/** Initialize your data structure here. */
Twitter() {
time = 0;
resentMax = 10;//题目要求10条
user.clear();
}
void init(int userId) {
user[userId].followee.clear();
user[userId].tweet.clear();
}
/** Compose a new tweet. */
void postTweet(int userId, int tweetId) {
if (user.find(userId) == user.end()) {
init(userId);//新用户
}
if (user[userId].tweet.size() == resentMax) {
user[userId].tweet.pop_back();//到达上限,删除链表尾部,距今最久远的推文
}
user[userId].tweet.push_front(tweetId);//在链表首部添加推文
tweetTime[tweetId] = ++time;//更新时间戳
}//创建一条新的推文
/** 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> ans;
for (list<int>::iterator it = user[userId].tweet.begin(); it != user[userId].tweet.end(); it++) {
ans.emplace_back(*it);
/*在执行emplace_back的时候,只调用了转移构造函数,在插入的时候直接构造,效率更高,减少额外空间的开辟
在执行push_back的时候,调用了构造和拷贝构造函数,因为在使用push_back()向容器中加入一个右值元素(临时对象)时,
首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数将这个临时对象放入容器中。原来的临时变量释放。
这样造成的问题就是临时变量申请资源的浪费。*/
}//将自己的推文都push进ans
for (int followeeId : user[userId].followee) {
if (followeeId == userId) continue;
vector<int> res;
list<int>::iterator it = user[followeeId].tweet.begin();
int i = 0;
while (i < ans.size() && it != user[followeeId].tweet.end()) {
if (tweetTime[*it] > tweetTime[ans[i]]) {
res.emplace_back(*it);
++it;
}
else {
res.emplace_back(ans[i]);
++i;
}
if (res.size() == resentMax) break;
}
for (; i < ans.size() && res.size() < resentMax; i++) res.emplace_back(ans[i]);
for (; it != user[followeeId].tweet.end() && res.size() < resentMax; it++) res.emplace_back(*it);
ans.assign(res.begin(), res.end());
}
return ans;
}
/** Follower follows a followee. If the operation is invalid, it should be a no-op. */
void follow(int followerId, int followeeId) {
if (user.find(followerId) == user.end()) init(followerId);
if (user.find(followeeId) == user.end()) init(followeeId);
user[followerId].followee.insert(followeeId);
}
/** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
void unfollow(int followerId, int followeeId) {
user[followerId].followee.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);
*/
int main() {
return 0;
}