We will use a file-sharing system to share a very large file consisting of m
small chunks with IDs from 1
to m
. When you join the system, the system should assign you a unique ID.
You are asked to implement the FileSharing
class:
FileSharing(int m)
Initializes the object with a file of m
chunks.int join(int[] ownedChunks)
: Adds a user to the system with an initial list of chunks ownedChunks
. The system should assign a unique ID to the user and returns it.void leave(int userID)
: Removes the user with ID userID
from the system and makes the ID available again.int[] request(int userID, int chunkID)
: Some user with ID userID
is requesting a chunk with ID chunkID
. Return a list of user IDs that own the given chunk.Example:
Input: ["FileSharing", "join", "join", "request", "request", "leave", "request", "request", "join", "request", "leave"] [[4], [[1,2]], [[2,3]], [1, 2], [2, 1], [1], [2, 2], [1, 2], [[1,2]], [2, 1], [2]] Output: [null, 1, 2, [1,2], [2], null, [2], [1,2], 3, [2,3], null] Explanation: FileSharing fileSharing = new FileSharing(4); fileSharing.join([1, 2]); // return 1 fileSharing.join([2, 3]); // return 2 fileSharing.request(1, 2); // return [1, 2] fileSharing.request(2, 1); // return [2] fileSharing.leave(1); // return null fileSharing.request(2, 2); // return [2] fileSharing.request(1, 2); // return [1, 2] fileSharing.join([1, 2]); // return 3 fileSharing.request(2, 1); // return [2, 3] fileSharing.leave(2); // return null
Constraints:
1 <= m, chunkID <= m
1 <= userID <= 105
0 <= ownedChunks.length <= m
1 <= ownedChunks[i] <= m
ownedChunks
are unique.leave
will have a matching call to join
.104
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
For designing a basic file sharing system, we can think of a brute force approach as trying every possible combination of servers and storage locations. We'll check if each combination meets our requirements, like speed or cost. If something isn't working well, we just try the next possibility until we find a fit.
Here's how the algorithm would work step-by-step:
def find_best_file_storage_brute_force(servers, storage_locations, file_access_speed_requirement, cost_requirement, reliability_requirement):
best_server = None
best_storage_location = None
best_overall_score = float('-inf')
for server in servers:
for storage_location in storage_locations:
# We have a specific configuration of server and location
current_file_access_speed = evaluate_file_access_speed(server, storage_location)
current_cost = evaluate_cost(server, storage_location)
current_reliability = evaluate_reliability(server, storage_location)
# See if the configuration meets file access speed criteria
if current_file_access_speed >= file_access_speed_requirement:
# We check if cost is acceptable
if current_cost <= cost_requirement:
# Is the system reliable enough for the requirements?
if current_reliability >= reliability_requirement:
# Calculating the score to choose the best config
overall_score = calculate_overall_score(current_file_access_speed, current_cost, current_reliability)
if overall_score > best_overall_score:
best_overall_score = overall_score
best_server = server
best_storage_location = storage_location
return best_server, best_storage_location
def evaluate_file_access_speed(server, storage_location):
return server["speed"] + storage_location["speed"]
def evaluate_cost(server, storage_location):
return server["cost"] + storage_location["cost"]
def evaluate_reliability(server, storage_location):
return server["reliability"] * storage_location["reliability"]
def calculate_overall_score(file_access_speed, cost, reliability):
return file_access_speed * reliability / cost
The file sharing system needs to handle uploading, downloading, and finding files efficiently. To do this, we'll use a combination of a central server to manage files and a way to split large files into smaller pieces for faster transfers.
Here's how the algorithm would work step-by-step:
import hashlib
class FileSharingSystem:
def __init__(self):
self.file_metadata = {}
self.file_chunks = {}
self.chunk_locations = {}
self.users = {}
def register_user(self, username, password):
hashed_password = hashlib.sha256(password.encode()).hexdigest()
self.users[username] = hashed_password
def login_user(self, username, password):
hashed_password = hashlib.sha256(password.encode()).hexdigest()
return username in self.users and self.users[username] == hashed_password
def upload_file(self, username, file_name, file_data, chunk_size=1024):
# Split file into chunks for efficient transfer
file_hash = hashlib.sha256(file_data.encode()).hexdigest()
self.file_metadata[file_hash] = {
'file_name': file_name,
'owner': username,
'file_size': len(file_data),
}
chunks = [file_data[i:i + chunk_size] for i in range(0, len(file_data), chunk_size)]
self.file_chunks[file_hash] = chunks
self.chunk_locations[file_hash] = {i: ['server1', 'server2'] for i in range(len(chunks))}
def download_file(self, file_hash, username):
if file_hash not in self.file_metadata:
return None, "File not found"
if self.file_metadata[file_hash]['owner'] != username:
return None, "Unauthorized"
if file_hash not in self.file_chunks:
return None, "File chunks not found"
# Assemble chunks to reconstruct the original file
file_data = ''.join(self.file_chunks[file_hash])
return file_data, None
def search_files(self, query):
results = {}
for file_hash, metadata in self.file_metadata.items():
if query.lower() in metadata['file_name'].lower():
results[file_hash] = metadata
return results
def get_file_metadata(self, file_hash):
if file_hash in self.file_metadata:
return self.file_metadata[file_hash]
else:
return None
def add_chunk_location(self, file_hash, chunk_index, server_name):
# Add chunk location for redundancy and availability
if file_hash in self.chunk_locations and chunk_index in self.chunk_locations[file_hash]:
self.chunk_locations[file_hash][chunk_index].append(server_name)
else:
return None
Case | How to Handle |
---|---|
n (number of users) is zero or negative. | Throw an IllegalArgumentException or similar error, as the system cannot function with zero or negative users. |
userId in join() is already registered. | Return immediately as user is already registered; alternatively, throw an exception if duplicate registration is considered an error. |
userId in leave(), upload(), or download() is not registered. | Return immediately as the action cannot be performed for an unregistered user, or throw an exception indicating invalid user. |
Empty parts list in upload(). | Treat as an empty file upload; create a new file ID, but store it as having no parts or return immediately based on requirements. |
fileId in download() or whoHas() does not exist. | Return an empty list in whoHas() or null/default value in download() to indicate the file doesn't exist, or throw an exception. |
User downloads a file and already has all parts of it. | Still record the download event to track popularity or activity, but no new parts need to be added to the user's inventory. |
A very large number of parts in upload(), exceeding memory constraints. | Implement pagination or chunking for file parts storage to handle arbitrarily large files and avoid memory overflow. |
Large number of users downloading the same file concurrently. | Implement concurrency control (e.g., using locks) to ensure data consistency when updating which users have file parts, or use an atomic data structure. |