Before attempting this problem, you should be comfortable with:
A file system has a natural tree structure where each directory can contain subdirectories and files. We model this by creating a Dir class that holds two hash maps: one for subdirectories and one for files. The root of the file system is a single Dir object. When we need to navigate to a path, we split it by "/" and traverse through the tree one directory at a time. This separation of directories and files makes it easy to distinguish between them when listing contents or reading file data.
Dir object with empty maps for subdirectories and files.Dir if it does not exist, then move into it.class FileSystem:
class Dir:
def __init__(self):
self.dirs = {}
self.files = {}
def __init__(self):
self.root = self.Dir()
def ls(self, path: str) -> List[str]:
t = self.root
files = []
if path != "/":
d = path.split("/")
for i in range(1, len(d) - 1):
t = t.dirs[d[i]]
if d[-1] in t.files:
files.append(d[-1])
return files
else:
t = t.dirs[d[-1]]
files.extend(t.dirs.keys())
files.extend(t.files.keys())
files.sort()
return files
def mkdir(self, path: str) -> None:
t = self.root
d = path.split("/")
for i in range(1, len(d)):
if d[i] not in t.dirs:
t.dirs[d[i]] = self.Dir()
t = t.dirs[d[i]]
def addContentToFile(self, filePath: str, content: str) -> None:
t = self.root
d = filePath.split("/")
for i in range(1, len(d) - 1):
t = t.dirs[d[i]]
if d[-1] not in t.files:
t.files[d[-1]] = ""
t.files[d[-1]] += content
def readContentFromFile(self, filePath: str) -> str:
t = self.root
d = filePath.split("/")
for i in range(1, len(d) - 1):
t = t.dirs[d[i]]
return t.files[d[-1]]The time complexity of executing an ls command :
ls, and is the number of entries(files + subdirectories) in the last level directory(in the current input)The time complexity of executing a mkdir command :
mkdirThe time complexity of both addContentToFile and readContentFromFile :
When the path is "/", splitting by "/" produces an empty string or array depending on the language. Failing to handle this case causes index errors or incorrect traversal.
# Wrong: assumes d[1] always exists
d = path.split("/")
t = t.dirs[d[1]] # IndexError when path is "/"
# Correct: check for root path first
if path != "/":
d = path.split("/")
for i in range(1, len(d)):
t = t.dirs[d[i]]The ls command must return just the file name (not contents) when the path points to a file, but return sorted directory contents when pointing to a directory. Mixing up these cases leads to wrong output.
# Wrong: always treating path as directory
return sorted(t.dirs.keys()) + sorted(t.files.keys())
# Correct: check if final component is a file
if d[-1] in t.files:
return [d[-1]] # Return just the filename
else:
t = t.dirs[d[-1]]
return sorted(list(t.dirs.keys()) + list(t.files.keys()))The addContentToFile method should append to existing content, not replace it. This is a common oversight that causes test failures.
# Wrong: overwrites existing content
t.files[filename] = content
# Correct: append to existing content
t.files[filename] = t.files.get(filename, "") + contentWhen navigating to a file's parent directory, you must stop one level before the final component. Traversing all the way causes you to look for the file as a directory.
# Wrong: traverses to the file itself (crashes if file isn't a directory)
for i in range(1, len(d)):
t = t.dirs[d[i]]
# Correct: stop before the last component
for i in range(1, len(d) - 1):
t = t.dirs[d[i]]
# Now access the file: t.files[d[-1]]The problem requires ls to return entries in lexicographical order. Forgetting to sort causes wrong answer even when the data structure is correct.
# Wrong: returns unsorted keys
return list(t.dirs.keys()) + list(t.files.keys())
# Correct: sort the combined result
files = list(t.dirs.keys()) + list(t.files.keys())
files.sort()
return filesInstead of maintaining separate maps for directories and files, we can use a single unified structure. Each node in our tree is a File object that can act as either a directory or a file. A boolean flag isFile tells us which role it plays. Directories store child nodes in a map, while files store their content in a string. This unified approach simplifies the data structure since we only need one type of node, and path traversal becomes more uniform.
File object with isFile = false and an empty children map.File nodes (as directories) along the way if they do not exist.class FileSystem:
class File:
def __init__(self):
self.isfile = False
self.files = {}
self.content = ""
def __init__(self):
self.root = self.File()
def ls(self, path: str) -> List[str]:
t = self.root
files = []
if path != "/":
d = path.split("/")
for i in range(1, len(d)):
t = t.files[d[i]]
if t.isfile:
files.append(d[-1])
return files
res_files = sorted(t.files.keys())
return res_files
def mkdir(self, path: str) -> None:
t = self.root
d = path.split("/")
for i in range(1, len(d)):
if d[i] not in t.files:
t.files[d[i]] = self.File()
t = t.files[d[i]]
def addContentToFile(self, filePath: str, content: str) -> None:
t = self.root
d = filePath.split("/")
for i in range(1, len(d) - 1):
t = t.files[d[i]]
if d[-1] not in t.files:
t.files[d[-1]] = self.File()
t = t.files[d[-1]]
t.isfile = True
t.content += content
def readContentFromFile(self, filePath: str) -> str:
t = self.root
d = filePath.split("/")
for i in range(1, len(d) - 1):
t = t.files[d[i]]
return t.files[d[-1]].contentThe time complexity of executing an ls command :
ls, and is the number of entries(files + subdirectories) in the last level directory(in the current input)The time complexity of executing a mkdir command :
mkdirThe time complexity of both addContentToFile and readContentFromFile :