1500. Design a File Sharing System 🔒
Problem Description
This problem asks you to design a file-sharing system that manages users and file chunks. The system needs to handle three main operations:
System Overview:
- A large file is divided into
m
chunks, numbered from 1 tom
- Users can join the system with certain chunks they already own
- Users can request chunks from other users
- Users can leave the system
Key Requirements:
-
User ID Management:
- When a user joins, assign them the smallest available positive integer ID
- IDs start from 1 and increment
- When a user leaves, their ID becomes available for reuse
- Reused IDs should be assigned before creating new higher IDs
-
Operations to Implement:
FileSharing(m)
: Initialize the system with a file containingm
chunksjoin(ownedChunks)
: Register a new user who owns the specified chunks, return their assigned IDleave(userID)
: Remove a user from the system, making their ID available for reuserequest(userID, chunkID)
: User requests a specific chunk- Returns a sorted list of all user IDs who own that chunk
- If the list is non-empty (meaning the chunk was found), the requesting user also receives the chunk
Example Walkthrough:
- User joins with chunks [1,2] → gets ID 1
- User joins with chunks [2,3] → gets ID 2
- User joins with chunk [4] → gets ID 3
- User 1 requests chunk 3 → gets [2] (only user 2 has it), now user 1 has chunks [1,2,3]
- User 2 requests chunk 2 → gets [1,2] (both users have it)
- User 1 leaves → ID 1 becomes available
- User 2 requests chunk 1 → gets [] (no one has it after user 1 left)
- New user joins → gets ID 1 (reused)
The solution uses a min-heap to efficiently track and reuse the smallest available user IDs, and a dictionary to map each user to their set of owned chunks. When requesting a chunk, it searches through all users to find owners and automatically adds the chunk to the requester if found.
Intuition
The key insight is that we need to efficiently manage two things: user IDs and chunk ownership. Let's think through each requirement:
For User ID Assignment: We need to always assign the smallest available ID. Initially, this seems simple - just use a counter starting at 1. But the challenge comes when users leave and we need to reuse their IDs. If users 1, 2, 3 exist and user 2 leaves, the next user should get ID 2, not ID 4.
This naturally leads us to use a min-heap to track available IDs. When a user leaves, we push their ID into the heap. When a new user joins, we first check if there are any reusable IDs in the heap (take the smallest one), otherwise increment our counter for a new ID.
For Chunk Ownership Tracking: We need to quickly answer "which users own chunk X?" and also track what chunks each user owns. A dictionary mapping user IDs to sets of chunks works perfectly here:
user_chunks[userID]
gives us all chunks a user owns- To find who owns a specific chunk, we iterate through all users and check if the chunk is in their set
Using a set for each user's chunks makes sense because:
- Checking if a user owns a chunk is O(1)
- Adding a new chunk when a request succeeds is O(1)
- The problem guarantees owned chunks are unique per user
For the Request Operation: When a user requests a chunk, we need to:
- Find all users who own it (iterate through our dictionary)
- If found, give the chunk to the requesting user
- Return the sorted list of owners
The sorting requirement at the end is straightforward - we collect all owner IDs in a list and sort before returning.
This approach balances simplicity with efficiency - we're not over-engineering with complex data structures, but we're using the right tools (heap for ID management, dictionary with sets for ownership) to make operations reasonably fast.
Learn more about Data Stream, Sorting and Heap (Priority Queue) patterns.
Solution Approach
Let's walk through the implementation step by step:
Data Structure Setup:
def __init__(self, m: int):
self.cur = 0 # Track the highest ID assigned so far
self.chunks = m # Total number of chunks in the file
self.reused = [] # Min-heap for reusable IDs
self.user_chunks = defaultdict(set) # Map userID -> set of owned chunks
We initialize four instance variables:
cur
: Counter for the next new ID to assign (when no reused IDs are available)chunks
: Store the total number of chunks for validationreused
: Min-heap to efficiently get the smallest reusable IDuser_chunks
: Dictionary mapping each user to their set of owned chunks
Join Operation:
def join(self, ownedChunks: List[int]) -> int:
if self.reused:
userID = heappop(self.reused) # Reuse smallest available ID
else:
self.cur += 1
userID = self.cur # Assign new ID
self.user_chunks[userID] = set(ownedChunks)
return userID
The algorithm follows this logic:
- Check if there are any reusable IDs in the heap
- If yes, pop the smallest one (min-heap property guarantees this)
- If no, increment
cur
and use it as the new ID - Store the user's chunks as a set in our dictionary
- Return the assigned ID
Leave Operation:
def leave(self, userID: int) -> None:
heappush(self.reused, userID) # Make ID available for reuse
self.user_chunks.pop(userID) # Remove user's chunk ownership
When a user leaves:
- Push their ID into the reused heap for future assignment
- Remove their entry from the user_chunks dictionary
Request Operation:
def request(self, userID: int, chunkID: int) -> List[int]:
if chunkID < 1 or chunkID > self.chunks:
return []
res = []
for k, v in self.user_chunks.items():
if chunkID in v:
res.append(k)
if res:
self.user_chunks[userID].add(chunkID)
return sorted(res)
The request logic:
- First validate the chunk ID is within valid range
[1, m]
- Iterate through all users in the system
- For each user, check if they own the requested chunk (O(1) set lookup)
- Collect all user IDs who own the chunk
- If at least one user owns it (non-empty result), add the chunk to the requester's set
- Return the sorted list of owner IDs
Time Complexity Analysis:
join
: O(log k) where k is the number of reused IDs, due to heap operationsleave
: O(log k) for heap push operationrequest
: O(n + n log n) where n is the number of users, for iterating through all users and sorting the result
Space Complexity:
- O(n × c) where n is the number of users and c is the average number of chunks per user
- Additional O(k) for the reused IDs heap
The solution elegantly handles ID reuse with a min-heap while maintaining efficient chunk ownership queries using sets, providing a good balance between implementation simplicity and performance.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through a small example to see how the solution works:
Initial Setup: FileSharing(4)
- System initialized with 4 chunks
cur = 0
,reused = []
(empty heap),user_chunks = {}
(empty dict)
Step 1: User joins with chunks [1, 3]
- Check
reused
heap - it's empty - Increment
cur
to 1, assign userID = 1 - Store
user_chunks[1] = {1, 3}
- Return 1
State: cur = 1
, reused = []
, user_chunks = {1: {1, 3}}
Step 2: User joins with chunks [2]
- Check
reused
heap - still empty - Increment
cur
to 2, assign userID = 2 - Store
user_chunks[2] = {2}
- Return 2
State: cur = 2
, reused = []
, user_chunks = {1: {1, 3}, 2: {2}}
Step 3: User 1 requests chunk 2
- Iterate through all users:
- User 1: chunk 2 not in {1, 3}
- User 2: chunk 2 IS in {2} ✓
- Result list = [2]
- Since result is non-empty, add chunk 2 to user 1:
user_chunks[1] = {1, 2, 3}
- Return sorted([2]) = [2]
State: user_chunks = {1: {1, 2, 3}, 2: {2}}
Step 4: User 2 leaves
- Push userID 2 into
reused
heap:heappush(reused, 2)
- Remove user 2:
user_chunks.pop(2)
State: cur = 2
, reused = [2]
, user_chunks = {1: {1, 2, 3}}
Step 5: New user joins with chunks [4]
- Check
reused
heap - contains [2] - Pop smallest ID:
userID = heappop(reused)
= 2 (ID reused!) - Store
user_chunks[2] = {4}
- Return 2
State: cur = 2
, reused = []
, user_chunks = {1: {1, 2, 3}, 2: {4}}
Step 6: User 2 requests chunk 3
- Iterate through all users:
- User 1: chunk 3 IS in {1, 2, 3} ✓
- User 2: chunk 3 not in {4}
- Result list = [1]
- Since result is non-empty, add chunk 3 to user 2:
user_chunks[2] = {3, 4}
- Return sorted([1]) = [1]
Final State: user_chunks = {1: {1, 2, 3}, 2: {3, 4}}
This example demonstrates:
- How the min-heap ensures we reuse the smallest available ID (user 2's ID was reused)
- How chunk ownership is tracked with sets for O(1) lookup
- How successful requests automatically grant the chunk to the requester
- How the system maintains sorted order in request results
Solution Implementation
1from collections import defaultdict
2from heapq import heappush, heappop
3from typing import List
4
5
6class FileSharing:
7 def __init__(self, m: int):
8 """
9 Initialize the file sharing system with m chunks.
10
11 Args:
12 m: Total number of chunks in the file
13 """
14 self.current_max_user_id = 0 # Track the highest user ID assigned
15 self.total_chunks = m # Total number of chunks in the file
16 self.reusable_user_ids = [] # Min heap to store reusable user IDs
17 self.user_to_chunks = defaultdict(set) # Map user ID to their owned chunks
18
19 def join(self, ownedChunks: List[int]) -> int:
20 """
21 Add a new user to the system with their initially owned chunks.
22
23 Args:
24 ownedChunks: List of chunk IDs that the user initially owns
25
26 Returns:
27 The assigned user ID
28 """
29 # Assign user ID - reuse if available, otherwise increment
30 if self.reusable_user_ids:
31 user_id = heappop(self.reusable_user_ids)
32 else:
33 self.current_max_user_id += 1
34 user_id = self.current_max_user_id
35
36 # Store the user's owned chunks
37 self.user_to_chunks[user_id] = set(ownedChunks)
38
39 return user_id
40
41 def leave(self, userID: int) -> None:
42 """
43 Remove a user from the system and make their ID available for reuse.
44
45 Args:
46 userID: The ID of the user leaving the system
47 """
48 # Add the user ID to the reusable pool
49 heappush(self.reusable_user_ids, userID)
50
51 # Remove the user's chunk ownership data
52 self.user_to_chunks.pop(userID)
53
54 def request(self, userID: int, chunkID: int) -> List[int]:
55 """
56 Request a specific chunk for a user and return list of users who own it.
57 If any users own the chunk, the requesting user also receives it.
58
59 Args:
60 userID: The ID of the user requesting the chunk
61 chunkID: The ID of the chunk being requested
62
63 Returns:
64 Sorted list of user IDs who own the requested chunk
65 """
66 # Validate chunk ID is within valid range
67 if chunkID < 1 or chunkID > self.total_chunks:
68 return []
69
70 # Find all users who own the requested chunk
71 users_with_chunk = []
72 for user_id, owned_chunks in self.user_to_chunks.items():
73 if chunkID in owned_chunks:
74 users_with_chunk.append(user_id)
75
76 # If chunk is available, give it to the requesting user
77 if users_with_chunk:
78 self.user_to_chunks[userID].add(chunkID)
79
80 # Return sorted list of users who had the chunk
81 return sorted(users_with_chunk)
82
83
84# Your FileSharing object will be instantiated and called as such:
85# obj = FileSharing(m)
86# param_1 = obj.join(ownedChunks)
87# obj.leave(userID)
88# param_3 = obj.request(userID, chunkID)
89
1class FileSharing {
2 // Total number of chunks in the file
3 private int totalChunks;
4
5 // Counter for assigning new user IDs
6 private int currentUserId;
7
8 // Set to store reusable user IDs (from users who left)
9 private TreeSet<Integer> reusableUserIds;
10
11 // Map to store each user's owned chunks: userId -> set of chunk IDs
12 private TreeMap<Integer, Set<Integer>> userToChunksMap;
13
14 /**
15 * Initialize the file sharing system with m chunks
16 * @param m the total number of chunks in the file
17 */
18 public FileSharing(int m) {
19 currentUserId = 0;
20 totalChunks = m;
21 reusableUserIds = new TreeSet<>();
22 userToChunksMap = new TreeMap<>();
23 }
24
25 /**
26 * A new user joins the system with initially owned chunks
27 * @param ownedChunks list of chunk IDs the user initially owns
28 * @return the assigned user ID
29 */
30 public int join(List<Integer> ownedChunks) {
31 int userId;
32
33 // Assign user ID: reuse an old ID if available, otherwise increment counter
34 if (reusableUserIds.isEmpty()) {
35 currentUserId++;
36 userId = currentUserId;
37 } else {
38 userId = reusableUserIds.pollFirst();
39 }
40
41 // Store the user's owned chunks
42 userToChunksMap.put(userId, new HashSet<>(ownedChunks));
43
44 return userId;
45 }
46
47 /**
48 * A user leaves the system
49 * @param userID the ID of the user leaving
50 */
51 public void leave(int userID) {
52 // Add the user ID back to reusable pool
53 reusableUserIds.add(userID);
54
55 // Remove the user's chunk ownership data
56 userToChunksMap.remove(userID);
57 }
58
59 /**
60 * A user requests a specific chunk from the system
61 * @param userID the ID of the requesting user
62 * @param chunkID the ID of the requested chunk
63 * @return sorted list of user IDs who own the requested chunk
64 */
65 public List<Integer> request(int userID, int chunkID) {
66 // Validate chunk ID is within valid range
67 if (chunkID < 1 || chunkID > totalChunks) {
68 return Collections.emptyList();
69 }
70
71 List<Integer> usersWithChunk = new ArrayList<>();
72
73 // Find all users who own the requested chunk
74 for (Map.Entry<Integer, Set<Integer>> entry : userToChunksMap.entrySet()) {
75 if (entry.getValue().contains(chunkID)) {
76 usersWithChunk.add(entry.getKey());
77 }
78 }
79
80 // If chunk is available, add it to the requesting user's owned chunks
81 if (!usersWithChunk.isEmpty()) {
82 userToChunksMap.computeIfAbsent(userID, k -> new HashSet<>()).add(chunkID);
83 }
84
85 return usersWithChunk;
86 }
87}
88
89/**
90 * Your FileSharing object will be instantiated and called as such:
91 * FileSharing obj = new FileSharing(m);
92 * int param_1 = obj.join(ownedChunks);
93 * obj.leave(userID);
94 * List<Integer> param_3 = obj.request(userID,chunkID);
95 */
96
1class FileSharing {
2private:
3 // Total number of chunks in the file
4 int totalChunks;
5
6 // Counter for assigning new user IDs
7 int currentUserId;
8
9 // Set to store reusable user IDs (from users who left)
10 set<int> reusableUserIds;
11
12 // Map to store each user's owned chunks: userId -> set of chunk IDs
13 map<int, set<int>> userToChunksMap;
14
15public:
16 /**
17 * Initialize the file sharing system with m chunks
18 * @param m the total number of chunks in the file
19 */
20 FileSharing(int m) {
21 currentUserId = 0;
22 totalChunks = m;
23 }
24
25 /**
26 * A new user joins the system with initially owned chunks
27 * @param ownedChunks list of chunk IDs the user initially owns
28 * @return the assigned user ID
29 */
30 int join(vector<int>& ownedChunks) {
31 int userId;
32
33 // Assign user ID: reuse an old ID if available, otherwise increment counter
34 if (reusableUserIds.empty()) {
35 currentUserId++;
36 userId = currentUserId;
37 } else {
38 userId = *reusableUserIds.begin();
39 reusableUserIds.erase(reusableUserIds.begin());
40 }
41
42 // Store the user's owned chunks
43 userToChunksMap[userId] = set<int>(ownedChunks.begin(), ownedChunks.end());
44
45 return userId;
46 }
47
48 /**
49 * A user leaves the system
50 * @param userID the ID of the user leaving
51 */
52 void leave(int userID) {
53 // Add the user ID back to reusable pool
54 reusableUserIds.insert(userID);
55
56 // Remove the user's chunk ownership data
57 userToChunksMap.erase(userID);
58 }
59
60 /**
61 * A user requests a specific chunk from the system
62 * @param userID the ID of the requesting user
63 * @param chunkID the ID of the requested chunk
64 * @return sorted list of user IDs who own the requested chunk
65 */
66 vector<int> request(int userID, int chunkID) {
67 // Validate chunk ID is within valid range
68 if (chunkID < 1 || chunkID > totalChunks) {
69 return vector<int>();
70 }
71
72 vector<int> usersWithChunk;
73
74 // Find all users who own the requested chunk
75 for (const auto& entry : userToChunksMap) {
76 if (entry.second.count(chunkID) > 0) {
77 usersWithChunk.push_back(entry.first);
78 }
79 }
80
81 // If chunk is available, add it to the requesting user's owned chunks
82 if (!usersWithChunk.empty()) {
83 userToChunksMap[userID].insert(chunkID);
84 }
85
86 return usersWithChunk;
87 }
88};
89
90/**
91 * Your FileSharing object will be instantiated and called as such:
92 * FileSharing* obj = new FileSharing(m);
93 * int param_1 = obj->join(ownedChunks);
94 * obj->leave(userID);
95 * vector<int> param_3 = obj->request(userID,chunkID);
96 */
97
1// Total number of chunks in the file
2let totalChunks: number;
3
4// Counter for assigning new user IDs
5let currentUserId: number;
6
7// Set to store reusable user IDs (from users who left)
8let reusableUserIds: Set<number>;
9
10// Map to store each user's owned chunks: userId -> set of chunk IDs
11let userToChunksMap: Map<number, Set<number>>;
12
13/**
14 * Initialize the file sharing system with m chunks
15 * @param m - the total number of chunks in the file
16 */
17function FileSharing(m: number): void {
18 currentUserId = 0;
19 totalChunks = m;
20 reusableUserIds = new Set<number>();
21 userToChunksMap = new Map<number, Set<number>>();
22}
23
24/**
25 * A new user joins the system with initially owned chunks
26 * @param ownedChunks - list of chunk IDs the user initially owns
27 * @returns the assigned user ID
28 */
29function join(ownedChunks: number[]): number {
30 let userId: number;
31
32 // Assign user ID: reuse an old ID if available, otherwise increment counter
33 if (reusableUserIds.size === 0) {
34 currentUserId++;
35 userId = currentUserId;
36 } else {
37 // Get the smallest reusable ID (TreeSet behavior)
38 userId = Math.min(...Array.from(reusableUserIds));
39 reusableUserIds.delete(userId);
40 }
41
42 // Store the user's owned chunks
43 userToChunksMap.set(userId, new Set<number>(ownedChunks));
44
45 return userId;
46}
47
48/**
49 * A user leaves the system
50 * @param userID - the ID of the user leaving
51 */
52function leave(userID: number): void {
53 // Add the user ID back to reusable pool
54 reusableUserIds.add(userID);
55
56 // Remove the user's chunk ownership data
57 userToChunksMap.delete(userID);
58}
59
60/**
61 * A user requests a specific chunk from the system
62 * @param userID - the ID of the requesting user
63 * @param chunkID - the ID of the requested chunk
64 * @returns sorted list of user IDs who own the requested chunk
65 */
66function request(userID: number, chunkID: number): number[] {
67 // Validate chunk ID is within valid range
68 if (chunkID < 1 || chunkID > totalChunks) {
69 return [];
70 }
71
72 const usersWithChunk: number[] = [];
73
74 // Find all users who own the requested chunk
75 for (const [userId, chunks] of userToChunksMap.entries()) {
76 if (chunks.has(chunkID)) {
77 usersWithChunk.push(userId);
78 }
79 }
80
81 // If chunk is available, add it to the requesting user's owned chunks
82 if (usersWithChunk.length > 0) {
83 if (!userToChunksMap.has(userID)) {
84 userToChunksMap.set(userID, new Set<number>());
85 }
86 userToChunksMap.get(userID)!.add(chunkID);
87 }
88
89 // Sort the list before returning (TreeMap behavior ensures sorted order)
90 return usersWithChunk.sort((a, b) => a - b);
91}
92
93/**
94 * Your FileSharing object will be instantiated and called as such:
95 * FileSharing(m);
96 * let param_1 = join(ownedChunks);
97 * leave(userID);
98 * let param_3 = request(userID, chunkID);
99 */
100
Time and Space Complexity
Time Complexity:
__init__(m)
:O(1)
- Simply initializes variables with constant time operations.join(ownedChunks)
:O(k + log n)
wherek
is the length ofownedChunks
andn
is the number of reused user IDs in the heap. The heap operationheappop
takesO(log n)
time, and creating a set fromownedChunks
takesO(k)
time.leave(userID)
:O(log n)
wheren
is the number of reused user IDs. Theheappush
operation takesO(log n)
time, and dictionary pop isO(1)
.request(userID, chunkID)
:O(u)
whereu
is the total number of active users. We iterate through all users inuser_chunks
to find those who own the chunk, which takesO(u)
time. The set membership check (chunkID in v
) isO(1)
for each user. Sorting the result takesO(u log u)
in the worst case when all users have the chunk, but since we're iterating through all users anyway, the overall complexity isO(u log u)
.
Space Complexity:
- Overall space:
O(u * c)
whereu
is the number of active users andc
is the average number of chunks per user. self.reused
:O(n)
wheren
is the number of left users (reused IDs in the heap).self.user_chunks
:O(u * c)
whereu
is the number of active users andc
is the average number of chunks each user owns.- The maximum possible space would be
O(u * m)
if all users own all chunks, wherem
is the total number of chunks.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Not Handling Edge Cases in Request Method
A common mistake is forgetting to handle the case where the requesting user already owns the chunk they're requesting. This could lead to duplicate additions or incorrect return values.
Pitfall Example:
def request(self, userID: int, chunkID: int) -> List[int]:
users_with_chunk = []
for user_id, owned_chunks in self.user_to_chunks.items():
if chunkID in owned_chunks:
users_with_chunk.append(user_id)
# Bug: Always adds chunk even if user already has it
if users_with_chunk:
self.user_to_chunks[userID].add(chunkID) # Set handles duplicates, but logic is unclear
return sorted(users_with_chunk)
Better Approach:
def request(self, userID: int, chunkID: int) -> List[int]:
if chunkID < 1 or chunkID > self.total_chunks:
return []
users_with_chunk = []
already_has_chunk = False
for user_id, owned_chunks in self.user_to_chunks.items():
if chunkID in owned_chunks:
users_with_chunk.append(user_id)
if user_id == userID:
already_has_chunk = True
# Only add if user doesn't already have it and someone else does
if users_with_chunk and not already_has_chunk:
self.user_to_chunks[userID].add(chunkID)
return sorted(users_with_chunk)
2. Incorrect User ID Reuse Logic
Many implementations fail to properly manage the reusable ID pool, especially when dealing with consecutive leave/join operations.
Pitfall Example:
def join(self, ownedChunks: List[int]) -> int:
# Bug: Not using a min-heap, just a list
if self.reusable_user_ids:
user_id = self.reusable_user_ids.pop() # Gets last element, not smallest!
else:
self.current_max_user_id += 1
user_id = self.current_max_user_id
self.user_to_chunks[user_id] = set(ownedChunks)
return user_id
Correct Implementation:
def join(self, ownedChunks: List[int]) -> int:
# Properly use heappop to get smallest ID
if self.reusable_user_ids:
user_id = heappop(self.reusable_user_ids)
else:
self.current_max_user_id += 1
user_id = self.current_max_user_id
self.user_to_chunks[user_id] = set(ownedChunks)
return user_id
3. Memory Leak from Not Cleaning Up After Leave
Forgetting to remove user data when they leave can cause memory leaks and incorrect results in future requests.
Pitfall Example:
def leave(self, userID: int) -> None:
heappush(self.reusable_user_ids, userID)
# Bug: Forgot to remove user's chunks!
# self.user_to_chunks still contains userID's data
Correct Implementation:
def leave(self, userID: int) -> None:
heappush(self.reusable_user_ids, userID)
# Must remove user's data to prevent memory leak and wrong results
if userID in self.user_to_chunks:
del self.user_to_chunks[userID]
4. Not Validating Chunk IDs
Failing to validate chunk IDs can lead to storing invalid chunks or returning incorrect results.
Pitfall Example:
def request(self, userID: int, chunkID: int) -> List[int]:
# Bug: No validation of chunkID
users_with_chunk = []
for user_id, owned_chunks in self.user_to_chunks.items():
if chunkID in owned_chunks:
users_with_chunk.append(user_id)
if users_with_chunk:
self.user_to_chunks[userID].add(chunkID) # Could add invalid chunk!
return sorted(users_with_chunk)
5. Using List Instead of Set for Chunk Storage
Using a list to store chunks leads to O(n) lookup time and potential duplicates.
Pitfall Example:
def __init__(self, m: int):
self.user_to_chunks = defaultdict(list) # Bug: Using list instead of set
def join(self, ownedChunks: List[int]) -> int:
# ...
self.user_to_chunks[user_id] = ownedChunks # O(n) lookups later!
Correct Approach:
def __init__(self, m: int):
self.user_to_chunks = defaultdict(set) # Use set for O(1) lookups
def join(self, ownedChunks: List[int]) -> int:
# ...
self.user_to_chunks[user_id] = set(ownedChunks) # Convert to set
What data structure does Breadth-first search typically uses to store intermediate states?
Recommended Readings
Median of Data Stream Given a stream of numbers find the median number at any given time accurate to 1 decimal place Example add_number 1 add_number 2 add_number 3 get_median 2 0 add_number 4 get_median 2 5 Try it yourself Explanation Intuition Brute force way is to sort the entire list every time we get a new number This would be O N log N for each add_number operation One step up is to notice that the list is sorted before we add any new number to it So every
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
https assets algo monster cover_photos heap svg Priority Queue and Heap What is the relationship between priority queue and heap Priority Queue is an Abstract Data Type and Heap is the concrete data structure we use to implement a priority queue Priority Queue A priority queue is a data structure
Want a Structured Path to Master System Design Too? Don’t Miss This!