大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。
题目
355. 设计推特
设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近 10 条推文。
实现 Twitter 类:
Twitter()初始化简易版推特对象void postTweet(int userId, int tweetId)根据给定的tweetId和userId创建一条新推文。每次调用此函数都会使用一个不同的tweetId。List<Integer> 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的用户。
示例:
输入
["Twitter", "postTweet", "getNewsFeed", "follow", "postTweet", "getNewsFeed", "unfollow", "getNewsFeed"]
[[], [1, 5], [1], [1, 2], [2, 6], [1], [1, 2], [1]]
输出
[null, null, [5], null, null, [6, 5], null, [5]]
解释
Twitter twitter = new Twitter();
twitter.postTweet(1, 5); // 用户 1 发送了一条新推文 (用户 id = 1, 推文 id = 5)
twitter.getNewsFeed(1); // 用户 1 的获取推文应当返回一个列表,其中包含一个 id 为 5 的推文
twitter.follow(1, 2); // 用户 1 关注了用户 2
twitter.postTweet(2, 6); // 用户 2 发送了一个新推文 (推文 id = 6)
twitter.getNewsFeed(1); // 用户 1 的获取推文应当返回一个列表,其中包含两个推文,id 分别为 -> [6, 5] 。推文 id 6 应当在推文 id 5 之前,因为它是在 5 之后发送的
twitter.unfollow(1, 2); // 用户 1 取消关注了用户 2
twitter.getNewsFeed(1); // 用户 1 获取推文应当返回一个列表,其中包含一个 id 为 5 的推文。因为用户 1 已经不再关注用户 2
提示:
1 <= userId, followerId, followeeId <= 5000 <= tweetId <= 104- 所有推特的 ID 都互不相同
postTweet、getNewsFeed、follow和unfollow方法最多调用3 * 104次
思路
-
这道题目看起来有点长,但是实际上就是需要实现四个方法:
(1)
follow关注方法,我们可以用Map来记录每个用户当前关注了那些人,键用当前用户的id, 值用数组存储,当用户新增了关注人时,先判断Map对象中存不存在有当前用户的相关记录,如果存在,那么直接在原本的记录中推送当前的用户,不过这道题目中需要做个去重;如果不存在,则新建一个数组,存储当前需要关注的用户id;(2)
unfollow取消关注方法,我们判断上一轮关注存储的Map中,当前需要取消关注的用户是否存在,如果存在删除掉记录,如果记录为空,那么删除掉当前用户的信息,避免后续判断是否需要新建数组的时候造成干扰;(3)
postTweet发布文章方法,同样用一个Map对象管理每个用户id的文章,记得发布文章的同时除了记录文章的id,还需要记录当前的时间,因为待会儿取出来的时候咱们对不同用户的文章排序时候需要用到,而且单纯拿当前的时间戳还不够,因为计算机可能一秒钟同时发布了几篇文章,所以咱们还得加多一个count变量来计算;(4)
getNewsFeed方法,先从follow的Map中,把当前用户的关注者,全部取出来,然后经过遍历,取出关注者的所有文章和当前用户的所有文章进行排序,取前十条;这道题目由于数据量可能很大, 我们就直接用一个数组来存储当前用户和所关注用户的所有文章,每次从各自的文章中取出最新发布的那篇来对比时间,重复进行10次即可。
实现
var Twitter = function() {
// 用Map数组来记录每个用户id的文章,实际上可能是存储在数据库的某张表中
this.map = new Map();
// 关注的也同样如此记录下来
this.followMap = new Map();
// 计算机的创建时间可以同一毫秒的
this.count = 0;
};
/**
* @param {number} userId
* @param {number} tweetId
* @return {void}
*/
Twitter.prototype.postTweet = function(userId, tweetId) {
// 如果存在的话,就在原本的基础unshift一条,不存在就新建
this.map.set(userId, [{ id: tweetId, createTime: new Date().getTime() + this.count }]
.concat(this.map.get(userId) || []));
this.count++;
};
/**
* @param {number} userId
* @return {number[]}
*/
Twitter.prototype.getNewsFeed = function(userId) {
// 用户及关注用户的列表
let userList = [ userId ].concat(this.followMap.get(userId) || []);
// 用户及关注用户的文章列表
let postList = userList.reduce((total, userId) => {
this.map.has(userId) && total.push([...this.map.get(userId)]);
return total;
}, []);
let result = [];
while (result.length < 10 && postList.length) {
let maxIndex = 0, maxValue = postList[0][0].createTime;
for (let i = 1; i < postList.length; i++) {
if (postList[i][0].createTime > maxValue) {
maxValue = postList[i][0].createTime;
maxIndex = i;
}
}
result.push(postList[maxIndex].shift().id);
!postList[maxIndex].length && postList.splice(maxIndex, 1);
}
return result;
};
/**
* @param {number} followerId
* @param {number} followeeId
* @return {void}
*/
Twitter.prototype.follow = function(followerId, followeeId) {
let followList = [ followeeId ].concat(this.followMap.get(followerId) || []);
this.followMap.set(followerId, [...new Set(followList)]);
};
/**
* @param {number} followerId
* @param {number} followeeId
* @return {void}
*/
Twitter.prototype.unfollow = function(followerId, followeeId) {
let followList = (this.followMap
.get(followerId) || [])
.filter(item => item !== followeeId);
if (!followList.length) {
this.followMap.delete(followerId);
} else {
this.followMap.set(followerId, followList);
}
};
/**
* Your Twitter object will be instantiated and called as such:
* var obj = new Twitter()
* obj.postTweet(userId,tweetId)
* var param_2 = obj.getNewsFeed(userId)
* obj.follow(followerId,followeeId)
* obj.unfollow(followerId,followeeId)
*/
结果
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。