Skip to content

Commit ff3a123

Browse files
feat: add NeetCode 150 - Heap/Priority Queue category
- Added 7 complete problems - All solutions include multiple approaches - Comprehensive explanations with complexity analysis
1 parent dce3e17 commit ff3a123

File tree

14 files changed

+1678
-0
lines changed

14 files changed

+1678
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Design Twitter
2+
3+
## Problem Statement
4+
5+
Design a simplified version of Twitter where users can post tweets, follow/unfollow another user, and see the 10 most recent tweets in the user's news feed.
6+
7+
Implement the Twitter class:
8+
9+
- `Twitter()` Initializes your twitter object.
10+
- `void postTweet(int userId, int tweetId)` Composes a new tweet with ID `tweetId` by the user `userId`. Each call to this function will be made with a unique `tweetId`.
11+
- `List<Integer> getNewsFeed(int userId)` Retrieves 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 themself. Tweets must be ordered from most recent to least recent.
12+
- `void follow(int followerId, int followeeId)` The user with ID `followerId` started following the user with ID `followeeId`.
13+
- `void unfollow(int followerId, int followeeId)` The user with ID `followerId` started unfollowing the user with ID `followeeId`.
14+
15+
## Examples
16+
17+
**Example 1:**
18+
```
19+
Input
20+
["Twitter", "postTweet", "getNewsFeed", "follow", "postTweet", "getNewsFeed", "unfollow", "getNewsFeed"]
21+
[[], [1, 5], [1], [1, 2], [2, 6], [1], [1, 2], [1]]
22+
23+
Output
24+
[null, null, [5], null, null, [6, 5], null, [5]]
25+
```
26+
27+
## Approach
28+
29+
### Method 1: HashMap + Priority Queue (Recommended)
30+
1. Use HashMap to store user tweets and followers
31+
2. Use PriorityQueue to get most recent tweets
32+
3. Merge tweets from followed users
33+
4. Return top 10 tweets
34+
35+
**Time Complexity:** O(k log n) - k tweets, n users
36+
**Space Complexity:** O(n) - n users and tweets
37+
38+
### Method 2: List + Sorting
39+
1. Use List to store tweets
40+
2. Sort by timestamp
41+
3. Filter by followed users
42+
4. Return top 10
43+
44+
**Time Complexity:** O(n log n) - Sorting
45+
**Space Complexity:** O(n) - All tweets
46+
47+
## Algorithm
48+
49+
```
50+
1. Store tweets in HashMap<userId, List<Tweet>>
51+
2. Store followers in HashMap<userId, Set<Integer>>
52+
3. For getNewsFeed:
53+
a. Get all followed users
54+
b. Collect tweets from all users
55+
c. Use PriorityQueue to get most recent
56+
d. Return top 10
57+
```
58+
59+
## Key Insights
60+
61+
- **HashMap**: Store user data efficiently
62+
- **PriorityQueue**: Get most recent tweets
63+
- **Timestamp**: Order tweets by time
64+
- **Merge**: Combine tweets from multiple users
65+
66+
## Alternative Approaches
67+
68+
1. **List + Sorting**: Use sorting for ordering
69+
2. **TreeMap**: Use TreeMap for ordering
70+
3. **Database**: Use database-like approach
71+
72+
## Edge Cases
73+
74+
- Empty news feed: Return empty list
75+
- No followers: Return own tweets
76+
- More than 10 tweets: Return top 10
77+
- Unfollow non-existent user: Handle gracefully
78+
79+
## Applications
80+
81+
- Social media platforms
82+
- Algorithm design patterns
83+
- Interview preparation
84+
- Data structure operations
85+
- System design
86+
87+
## Optimization Opportunities
88+
89+
- **HashMap**: Most efficient storage
90+
- **PriorityQueue**: Efficient ordering
91+
- **Merge**: Combine tweets efficiently
92+
- **Caching**: Cache news feed results
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/**
2+
* Time Complexity: O(k log n) - k tweets, n users
3+
* Space Complexity: O(n) - n users and tweets
4+
*/
5+
class Twitter {
6+
private Map<Integer, List<Tweet>> userTweets;
7+
private Map<Integer, Set<Integer>> userFollowers;
8+
private int timestamp;
9+
10+
public Twitter() {
11+
userTweets = new HashMap<>();
12+
userFollowers = new HashMap<>();
13+
timestamp = 0;
14+
}
15+
16+
public void postTweet(int userId, int tweetId) {
17+
if (!userTweets.containsKey(userId)) {
18+
userTweets.put(userId, new ArrayList<>());
19+
}
20+
userTweets.get(userId).add(new Tweet(tweetId, timestamp++));
21+
}
22+
23+
public List<Integer> getNewsFeed(int userId) {
24+
PriorityQueue<Tweet> maxHeap = new PriorityQueue<>((a, b) -> b.timestamp - a.timestamp);
25+
26+
// Add user's own tweets
27+
if (userTweets.containsKey(userId)) {
28+
for (Tweet tweet : userTweets.get(userId)) {
29+
maxHeap.offer(tweet);
30+
}
31+
}
32+
33+
// Add tweets from followed users
34+
if (userFollowers.containsKey(userId)) {
35+
for (int followeeId : userFollowers.get(userId)) {
36+
if (userTweets.containsKey(followeeId)) {
37+
for (Tweet tweet : userTweets.get(followeeId)) {
38+
maxHeap.offer(tweet);
39+
}
40+
}
41+
}
42+
}
43+
44+
List<Integer> result = new ArrayList<>();
45+
int count = 0;
46+
while (!maxHeap.isEmpty() && count < 10) {
47+
result.add(maxHeap.poll().tweetId);
48+
count++;
49+
}
50+
51+
return result;
52+
}
53+
54+
public void follow(int followerId, int followeeId) {
55+
if (!userFollowers.containsKey(followerId)) {
56+
userFollowers.put(followerId, new HashSet<>());
57+
}
58+
userFollowers.get(followerId).add(followeeId);
59+
}
60+
61+
public void unfollow(int followerId, int followeeId) {
62+
if (userFollowers.containsKey(followerId)) {
63+
userFollowers.get(followerId).remove(followeeId);
64+
}
65+
}
66+
67+
private static class Tweet {
68+
int tweetId;
69+
int timestamp;
70+
71+
Tweet(int tweetId, int timestamp) {
72+
this.tweetId = tweetId;
73+
this.timestamp = timestamp;
74+
}
75+
}
76+
}
77+
78+
// Alternative approach using List + Sorting
79+
class TwitterList {
80+
private Map<Integer, List<Tweet>> userTweets;
81+
private Map<Integer, Set<Integer>> userFollowers;
82+
private int timestamp;
83+
84+
public TwitterList() {
85+
userTweets = new HashMap<>();
86+
userFollowers = new HashMap<>();
87+
timestamp = 0;
88+
}
89+
90+
public void postTweet(int userId, int tweetId) {
91+
if (!userTweets.containsKey(userId)) {
92+
userTweets.put(userId, new ArrayList<>());
93+
}
94+
userTweets.get(userId).add(new Tweet(tweetId, timestamp++));
95+
}
96+
97+
public List<Integer> getNewsFeed(int userId) {
98+
List<Tweet> allTweets = new ArrayList<>();
99+
100+
// Add user's own tweets
101+
if (userTweets.containsKey(userId)) {
102+
allTweets.addAll(userTweets.get(userId));
103+
}
104+
105+
// Add tweets from followed users
106+
if (userFollowers.containsKey(userId)) {
107+
for (int followeeId : userFollowers.get(userId)) {
108+
if (userTweets.containsKey(followeeId)) {
109+
allTweets.addAll(userTweets.get(followeeId));
110+
}
111+
}
112+
}
113+
114+
// Sort by timestamp (most recent first)
115+
allTweets.sort((a, b) -> b.timestamp - a.timestamp);
116+
117+
List<Integer> result = new ArrayList<>();
118+
for (int i = 0; i < Math.min(10, allTweets.size()); i++) {
119+
result.add(allTweets.get(i).tweetId);
120+
}
121+
122+
return result;
123+
}
124+
125+
public void follow(int followerId, int followeeId) {
126+
if (!userFollowers.containsKey(followerId)) {
127+
userFollowers.put(followerId, new HashSet<>());
128+
}
129+
userFollowers.get(followerId).add(followeeId);
130+
}
131+
132+
public void unfollow(int followerId, int followeeId) {
133+
if (userFollowers.containsKey(followerId)) {
134+
userFollowers.get(followerId).remove(followeeId);
135+
}
136+
}
137+
138+
private static class Tweet {
139+
int tweetId;
140+
int timestamp;
141+
142+
Tweet(int tweetId, int timestamp) {
143+
this.tweetId = tweetId;
144+
this.timestamp = timestamp;
145+
}
146+
}
147+
}
148+
149+
// Alternative approach using TreeMap
150+
class TwitterTreeMap {
151+
private Map<Integer, List<Tweet>> userTweets;
152+
private Map<Integer, Set<Integer>> userFollowers;
153+
private int timestamp;
154+
155+
public TwitterTreeMap() {
156+
userTweets = new HashMap<>();
157+
userFollowers = new HashMap<>();
158+
timestamp = 0;
159+
}
160+
161+
public void postTweet(int userId, int tweetId) {
162+
if (!userTweets.containsKey(userId)) {
163+
userTweets.put(userId, new ArrayList<>());
164+
}
165+
userTweets.get(userId).add(new Tweet(tweetId, timestamp++));
166+
}
167+
168+
public List<Integer> getNewsFeed(int userId) {
169+
TreeMap<Integer, List<Tweet>> tweetMap = new TreeMap<>(Collections.reverseOrder());
170+
171+
// Add user's own tweets
172+
if (userTweets.containsKey(userId)) {
173+
for (Tweet tweet : userTweets.get(userId)) {
174+
tweetMap.computeIfAbsent(tweet.timestamp, k -> new ArrayList<>()).add(tweet);
175+
}
176+
}
177+
178+
// Add tweets from followed users
179+
if (userFollowers.containsKey(userId)) {
180+
for (int followeeId : userFollowers.get(userId)) {
181+
if (userTweets.containsKey(followeeId)) {
182+
for (Tweet tweet : userTweets.get(followeeId)) {
183+
tweetMap.computeIfAbsent(tweet.timestamp, k -> new ArrayList<>()).add(tweet);
184+
}
185+
}
186+
}
187+
}
188+
189+
List<Integer> result = new ArrayList<>();
190+
int count = 0;
191+
for (List<Tweet> tweets : tweetMap.values()) {
192+
for (Tweet tweet : tweets) {
193+
if (count >= 10) break;
194+
result.add(tweet.tweetId);
195+
count++;
196+
}
197+
if (count >= 10) break;
198+
}
199+
200+
return result;
201+
}
202+
203+
public void follow(int followerId, int followeeId) {
204+
if (!userFollowers.containsKey(followerId)) {
205+
userFollowers.put(followerId, new HashSet<>());
206+
}
207+
userFollowers.get(followerId).add(followeeId);
208+
}
209+
210+
public void unfollow(int followerId, int followeeId) {
211+
if (userFollowers.containsKey(followerId)) {
212+
userFollowers.get(followerId).remove(followeeId);
213+
}
214+
}
215+
216+
private static class Tweet {
217+
int tweetId;
218+
int timestamp;
219+
220+
Tweet(int tweetId, int timestamp) {
221+
this.tweetId = tweetId;
222+
this.timestamp = timestamp;
223+
}
224+
}
225+
}

0 commit comments

Comments
 (0)