You are asked to design a file system which provides two functions:
createPath(path, value)
: Creates a new path and associates a value to it.get(path)
: Returns the value associated with a path or returns -1
if the path doesn't exist.The path is the absolute path represented as a string following this format: /
one/two/three. For example, /leetcode
and /leetcode/problems
are valid paths while an empty string ""
, /
, //
and /one//two
are not.
Implement the FileSystem
class:
FileSystem()
Initializes the object of the system.bool createPath(string path, int value)
Creates a new path
with the given value
. Returns true
if the path was not existent and was successfully created, or false
if the path already exists.int get(string path)
Returns the value associated with the path
or returns -1
if the path doesn't exist.Example 1:
Input: ["FileSystem","createPath","get","createPath","get"] [[],["/a",1],["/a"],["/a/b",2],["/b"]] Output: [null,true,1,true,-1] Explanation: FileSystem fileSystem = new FileSystem(); fileSystem.createPath("/a", 1); // return true fileSystem.get("/a"); // return 1 fileSystem.createPath("/a/b", 2); // return true fileSystem.get("/b"); // return -1. "/b" does not exist.
Example 2:
Input: ["FileSystem","createPath","createPath","get","createPath","get"] [[],["/leet",1],["/leet/code",10],["/leet/code"],["/c/d",1],["/c"]] Output: [null,true,true,10,true,-1]
Constraints:
1 <= path.length <= 100
1 <= value <= 109
1000
times./one/two/three
.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:
The simplest approach is to maintain a single master list of all the file paths and their corresponding values. For any action, like creating a new file or finding an existing one, we just search through this entire list from top to bottom every single time.
Here's how the algorithm would work step-by-step:
class FileSystem:
def __init__(self):
self.paths_and_values = []
def createPath(self, path, value):
if not path or path == "/" or not path.startswith("/"):
return False
# We must check our whole collection to make sure the path we want to create doesn't already exist.
for existing_path, _ in self.paths_and_values:
if existing_path == path:
return False
last_slash_index = path.rfind("/")
if last_slash_index == 0:
parent_path = "/"
else:
parent_path = path[:last_slash_index]
# A new path is only valid if its parent exists, so we must exhaustively search for it.
parent_path_exists = False
if parent_path == "/":
parent_path_exists = True
else:
for existing_path, _ in self.paths_and_values:
if existing_path == parent_path:
parent_path_exists = True
break
if parent_path_exists:
self.paths_and_values.append((path, value))
return True
return False
def get(self, path):
# To get a value, we search the entire collection from the start until we find an exact match.
for stored_path, stored_value in self.paths_and_values:
if stored_path == path:
return stored_value
return -1
The core idea is to model the file system like a branching tree of folders. We use a nested, map-like structure where each name points to another map representing its contents, allowing us to easily follow a path from the root down to its destination.
Here's how the algorithm would work step-by-step:
class FileSystem:
def __init__(self):
self.file_system_root = {}
def createPath(self, path, value):
path_components = [component for component in path.split('/') if component]
if not path_components:
return False
parent_path_components = path_components[:-1]
final_item_name = path_components[-1]
current_directory = self.file_system_root
for directory_name in parent_path_components:
if directory_name not in current_directory:
return False
current_directory = current_directory[directory_name]
# A path component must be a directory (a dict), not a file, to navigate into it.
if not isinstance(current_directory, dict):
return False
# To prevent overwrites, the new item cannot already exist in the parent directory.
if final_item_name in current_directory:
return False
current_directory[final_item_name] = value
return True
def get(self, path):
path_components = [component for component in path.split('/') if component]
current_node = self.file_system_root
for component_name in path_components:
# The traversal fails if a directory in the path does not exist or is actually a file.
if not isinstance(current_node, dict) or component_name not in current_node:
return -1
current_node = current_node[component_name]
# A value can only be retrieved from a file (an int), not from a directory (a dict).
if isinstance(current_node, dict):
return -1
return current_node
Case | How to Handle |
---|---|
Creating a path where its parent path does not exist, e.g., createPath("/a/b", 1) when "/a" hasn't been created. | The operation must fail and return false, as the parent path must exist before a child path can be created. |
Attempting to create a path that already exists, e.g., createPath("/a", 2) after createPath("/a", 1) was successful. | This call should return false, and the original value associated with the path must remain unchanged. |
Input paths that are invalid according to the problem description, such as an empty string "", the root "/", or paths with consecutive slashes like "/a//b". | These malformed paths should be rejected immediately, with createPath returning false and get returning -1. |
Creating a path that is a direct child of the root, like "/a". | The parent-finding logic must correctly identify the root "/", which is considered to always exist, allowing the creation. |
Requesting the value of a path that serves as a parent but was never explicitly created with a value, e.g., get("/a") after creating "/a/b". | This should return -1 because the existence of a child path does not implicitly create a value for its parent. |
Path strings that include a trailing slash, such as "/a/". | The system should normalize paths by removing any trailing slashes to treat "/a" and "/a/" as identical. |
The shortest possible valid path, consisting of a single component like "/a". | The logic must correctly handle this minimal case, identifying its parent as the root path "/". |
Operations performed directly on the root path, i.e., createPath("/", 1) or get("/"). | The root path itself cannot have an associated value, so these operations should consistently fail. |