355设计推特

小鱼儿 2023-02-26 13:23 91阅读 0赞

一、前言

分类:Hash Table。

问题来源LeetCode 355 难度:中等。

问题链接:https://leetcode-cn.com/problems/design-twitter/

二、题目

设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文。你的设计需要支持以下的几个功能:

  1. postTweet(userId, tweetId): 创建一条新的推文
  2. getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由此用户关注的人或者是用户自己发出的。推文必须按照时间顺序由最近的开始排序。
  3. follow(followerId, followeeId): 关注一个用户
  4. unfollow(followerId, followeeId): 取消关注一个用户

示例:

  1. Twitter twitter = new Twitter();
  2. // 用户1发送了一条新推文 (用户id = 1, 推文id = 5).
  3. twitter.postTweet(1, 5);
  4. // 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
  5. twitter.getNewsFeed(1);
  6. // 用户1关注了用户2.
  7. twitter.follow(1, 2);
  8. // 用户2发送了一个新推文 (推文id = 6).
  9. twitter.postTweet(2, 6);
  10. // 用户1的获取推文应当返回一个列表,其中包含两个推文,id分别为 -> [6, 5].
  11. // 推文id6应当在推文id5之前,因为它是在5之后发送的.
  12. twitter.getNewsFeed(1);
  13. // 用户1取消关注了用户2.
  14. twitter.unfollow(1, 2);
  15. // 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
  16. // 因为用户1已经不再关注用户2.
  17. twitter.getNewsFeed(1);

三、思路

用 哈希表 + 链表 解决这道问题。

四、编码实现

  1. //==========================================================================
  2. /*
  3. * @file : 355_Twitter.h
  4. * @blogs :
  5. * @author : niebingyu
  6. * @date : 2020/07/15
  7. * @title : 355. 设计推特
  8. * @purpose : 设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文。你的设计需要支持以下的几个功能:
  9. * postTweet(userId, tweetId): 创建一条新的推文
  10. * getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由此用户关注的人或者是用户自己发出的。推文必须按照时间顺序由最近的开始排序。
  11. * follow(followerId, followeeId): 关注一个用户
  12. * unfollow(followerId, followeeId): 取消关注一个用户
  13. *
  14. * 示例:
  15. * Twitter twitter = new Twitter();
  16. *
  17. * // 用户1发送了一条新推文 (用户id = 1, 推文id = 5).
  18. * twitter.postTweet(1, 5);
  19. *
  20. * // 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
  21. * twitter.getNewsFeed(1);
  22. *
  23. * // 用户1关注了用户2.
  24. * twitter.follow(1, 2);
  25. *
  26. * // 用户2发送了一个新推文 (推文id = 6).
  27. * twitter.postTweet(2, 6);
  28. *
  29. * // 用户1的获取推文应当返回一个列表,其中包含两个推文,id分别为 -> [6, 5].
  30. * // 推文id6应当在推文id5之前,因为它是在5之后发送的.
  31. * twitter.getNewsFeed(1);
  32. *
  33. // 用户1取消关注了用户2.
  34. * twitter.unfollow(1, 2);
  35. // 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
  36. // 因为用户1已经不再关注用户2.
  37. * twitter.getNewsFeed(1);
  38. *
  39. *
  40. * 来源:力扣(LeetCode)
  41. * 难度:简单
  42. * 链接:https://leetcode-cn.com/problems/design-twitter
  43. */
  44. //==========================================================================
  45. #pragma once
  46. #include <iostream>
  47. #include <unordered_set>
  48. #include <unordered_map>
  49. #include <algorithm>
  50. using namespace std;
  51. #define NAMESPACE_TWITTER namespace NAME_TWITTER {
  52. #define NAMESPACE_TWITTEREND }
  53. NAMESPACE_TWITTER
  54. class Twitter
  55. {
  56. struct Node
  57. {
  58. // 哈希表存储关注人的 Id
  59. unordered_set<int> followee;
  60. // 用链表存储 tweetId
  61. list<int> tweet;
  62. };
  63. // getNewsFeed 检索的推文的上限以及 tweetId 的时间戳
  64. int recentMax, time;
  65. // tweetId 对应发送的时间
  66. unordered_map<int, int> tweetTime;
  67. // 每个用户存储的信息
  68. unordered_map<int, Node> user;
  69. public:
  70. Twitter()
  71. {
  72. time = 0;
  73. recentMax = 10;
  74. user.clear();
  75. }
  76. // 初始化
  77. void init(int userId)
  78. {
  79. user[userId].followee.clear();
  80. user[userId].tweet.clear();
  81. }
  82. void postTweet(int userId, int tweetId)
  83. {
  84. if (user.find(userId) == user.end())
  85. init(userId);
  86. // 达到限制,剔除链表末尾元素
  87. if (user[userId].tweet.size() == recentMax)
  88. user[userId].tweet.pop_back();
  89. user[userId].tweet.push_front(tweetId);
  90. tweetTime[tweetId] = ++time;
  91. }
  92. vector<int> getNewsFeed(int userId)
  93. {
  94. vector<int> ans; ans.clear();
  95. for (list<int>::iterator it = user[userId].tweet.begin(); it != user[userId].tweet.end(); ++it)
  96. ans.emplace_back(*it);
  97. for (int followeeId: user[userId].followee)
  98. {
  99. if (followeeId == userId) continue; // 可能出现自己关注自己的情况
  100. vector<int> res; res.clear();
  101. list<int>::iterator it = user[followeeId].tweet.begin();
  102. int i = 0;
  103. // 线性归并
  104. while (i < (int)ans.size() && it != user[followeeId].tweet.end())
  105. {
  106. if (tweetTime[(*it)] > tweetTime[ans[i]])
  107. {
  108. res.emplace_back(*it);
  109. ++it;
  110. }
  111. else
  112. {
  113. res.emplace_back(ans[i]);
  114. ++i;
  115. }
  116. // 已经找到这两个链表合起来后最近的 recentMax 条推文
  117. if ((int)res.size() == recentMax)
  118. break;
  119. }
  120. for (; i < (int)ans.size() && (int)res.size() < recentMax; ++i) res.emplace_back(ans[i]);
  121. for (; it != user[followeeId].tweet.end() && (int)res.size() < recentMax; ++it) res.emplace_back(*it);
  122. ans.assign(res.begin(),res.end());
  123. }
  124. return ans;
  125. }
  126. void follow(int followerId, int followeeId)
  127. {
  128. if (user.find(followerId) == user.end())
  129. init(followerId);
  130. if (user.find(followeeId) == user.end())
  131. init(followeeId);
  132. user[followerId].followee.insert(followeeId);
  133. }
  134. void unfollow(int followerId, int followeeId)
  135. {
  136. user[followerId].followee.erase(followeeId);
  137. }
  138. };
  139. 以下为测试代码//
  140. // 测试 用例 START
  141. // tweet: 发送推特, followee,关注
  142. void test(const char* testName, vector<pair<int, int>>& tweet, vector<pair<int, int>>& followee, int feedID, vector<int>& expect)
  143. {
  144. Twitter twitter;
  145. for (auto it: tweet)
  146. twitter.postTweet(it.first, it.second);
  147. for (auto it : followee)
  148. twitter.follow(it.first, it.second);
  149. vector<int> result = twitter.getNewsFeed(feedID);
  150. if (expect == result)
  151. cout << testName << ", solution passed." << endl;
  152. else
  153. cout << testName << ", solution failed." << endl;
  154. }
  155. // 发送推特
  156. vector<pair<int, int>> tweet1 =
  157. {
  158. {1,101},
  159. {1,102},
  160. {2,103},
  161. {3,104},
  162. {1,105},
  163. {3,106},
  164. {1,107},
  165. {2,108},
  166. {4,109},
  167. {3,110},
  168. {3,111},
  169. {3,112},
  170. {2,113},
  171. {4,114},
  172. {3,115},
  173. {5,116},
  174. {5,117},
  175. {5,118}
  176. };
  177. // 测试用例
  178. void Test1()
  179. {
  180. vector<pair<int, int>> followee =
  181. {
  182. {1,2},
  183. {2,3},
  184. {2,4},
  185. {2,5},
  186. {2,5}
  187. };
  188. int feedID = 1;
  189. vector<int> expect = {113,108,107,105,103,102,101};
  190. test("Test1()", tweet1, followee, feedID, expect);
  191. }
  192. void Test2()
  193. {
  194. vector<pair<int, int>> followee =
  195. {
  196. {1,2},
  197. {2,3},
  198. {2,4},
  199. {2,5},
  200. {1,5}
  201. };
  202. int feedID = 1;
  203. vector<int> expect = { 118,117,116,113,108,107,105,103,102,101 };
  204. test("Test2()", tweet1, followee, feedID, expect);
  205. }
  206. void Test3()
  207. {
  208. vector<pair<int, int>> followee =
  209. {
  210. {1,2},
  211. {1,3},
  212. {1,4},
  213. {1,5},
  214. {1,1}
  215. };
  216. int feedID = 1;
  217. vector<int> expect = { 118,117,116,115,114,113,112,111,110,109 };
  218. test("Test3()", tweet1, followee, feedID, expect);
  219. }
  220. NAMESPACE_TWITTEREND
  221. // 测试 用例 END
  222. //
  223. void Twitter_Test()
  224. {
  225. NAME_TWITTER::Test1();
  226. NAME_TWITTER::Test2();
  227. NAME_TWITTER::Test3();
  228. }

执行结果:

20200715203311425.png

发表评论

表情:
评论列表 (有 0 条评论,91人围观)

还没有评论,来说两句吧...

相关阅读

    相关 每日一题-设计

    今天是2020年4月13日,星期一。 题目描述 设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近

    相关 leetcode355 设计

    设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文。你的设计需要支持以下的几个功能: postT

    相关 Twitter高级搜索

    今天,尝试通过模拟浏览器爬取推特数据。想要爬取包括不同关键词的推文,比如含有“home”或者“school”其中的一个,再或者需要指定发推的时间,那么我们需要用到推特的高级搜索