Design a data structure that simulates an in-memory file system.
Implement the FileSystem class:
FileSystem() Initializes the object of the system.
List<String> ls(String path)
If path is a file path, returns a list that only contains this file's name.
If path is a directory path, returns the list of file and directory names in this directory.
The answer should in lexicographic order.
void mkdir(String path) Makes a new directory according to the given path. The given directory path does not exist. If the middle directories in the path do not exist, you should create them as well.
path and filePath are absolute paths which begin with '/' and do not end with '/' except that the path is just "/".
You can assume that all directory names and file names only contain lowercase letters, and the same names will not exist in the same directory.
You can assume that all operations will be passed valid parameters, and users will not attempt to retrieve file content or list a directory or file that does not exist.
You can assume that the parent directory for the file in addContentToFile will exist.
1 <= content.length <= 50
At most 300 calls will be made to ls, mkdir, addContentToFile, and readContentFromFile.
Solutions
Solution 1
Thinking
A file system is hierarchical: list, mkdir, append, read. A flat map of full paths works, but sharing prefixes and listing a directory is awkward.
A trie keyed by path segments stores children, a file flag, and content chunks. insert creates nodes; search walks to the target. ls returns a file name or the sorted child names. Cost follows path depth.
classTrie:def__init__(self):self.name=Noneself.isFile=Falseself.content=[]self.children={}definsert(self,path,isFile):node=selfps=path.split('/')forpinps[1:]:ifpnotinnode.children:node.children[p]=Trie()node=node.children[p]node.isFile=isFileifisFile:node.name=ps[-1]returnnodedefsearch(self,path):node=selfifpath=='/':returnnodeps=path.split('/')forpinps[1:]:ifpnotinnode.children:returnNonenode=node.children[p]returnnodeclassFileSystem:def__init__(self):self.root=Trie()defls(self,path:str)->List[str]:node=self.root.search(path)ifnodeisNone:return[]ifnode.isFile:return[node.name]returnsorted(node.children.keys())defmkdir(self,path:str)->None:self.root.insert(path,False)defaddContentToFile(self,filePath:str,content:str)->None:node=self.root.insert(filePath,True)node.content.append(content)defreadContentFromFile(self,filePath:str)->str:node=self.root.search(filePath)return''.join(node.content)# Your FileSystem object will be instantiated and called as such:# obj = FileSystem()# param_1 = obj.ls(path)# obj.mkdir(path)# obj.addContentToFile(filePath,content)# param_4 = obj.readContentFromFile(filePath)
classTrie{Stringname;booleanisFile;StringBuildercontent=newStringBuilder();Map<String,Trie>children=newHashMap<>();Trieinsert(Stringpath,booleanisFile){Trienode=this;String[]ps=path.split("/");for(inti=1;i<ps.length;++i){Stringp=ps[i];if(!node.children.containsKey(p)){node.children.put(p,newTrie());}node=node.children.get(p);}node.isFile=isFile;if(isFile){node.name=ps[ps.length-1];}returnnode;}Triesearch(Stringpath){Trienode=this;String[]ps=path.split("/");for(inti=1;i<ps.length;++i){Stringp=ps[i];if(!node.children.containsKey(p)){returnnull;}node=node.children.get(p);}returnnode;}}classFileSystem{privateTrieroot=newTrie();publicFileSystem(){}publicList<String>ls(Stringpath){List<String>ans=newArrayList<>();Trienode=root.search(path);if(node==null){returnans;}if(node.isFile){ans.add(node.name);returnans;}for(Stringv:node.children.keySet()){ans.add(v);}Collections.sort(ans);returnans;}publicvoidmkdir(Stringpath){root.insert(path,false);}publicvoidaddContentToFile(StringfilePath,Stringcontent){Trienode=root.insert(filePath,true);node.content.append(content);}publicStringreadContentFromFile(StringfilePath){Trienode=root.search(filePath);returnnode.content.toString();}}/** * Your FileSystem object will be instantiated and called as such: * FileSystem obj = new FileSystem(); * List<String> param_1 = obj.ls(path); * obj.mkdir(path); * obj.addContentToFile(filePath,content); * String param_4 = obj.readContentFromFile(filePath); */
typeTriestruct{namestringisFileboolcontentstrings.Builderchildrenmap[string]*Trie}funcnewTrie()*Trie{m:=map[string]*Trie{}return&Trie{children:m}}func(this*Trie)insert(pathstring,isFilebool)*Trie{node:=thisps:=strings.Split(path,"/")for_,p:=rangeps[1:]{if_,ok:=node.children[p];!ok{node.children[p]=newTrie()}node,_=node.children[p]}node.isFile=isFileifisFile{node.name=ps[len(ps)-1]}returnnode}func(this*Trie)search(pathstring)*Trie{ifpath=="/"{returnthis}node:=thisps:=strings.Split(path,"/")for_,p:=rangeps[1:]{if_,ok:=node.children[p];!ok{returnnil}node,_=node.children[p]}returnnode}typeFileSystemstruct{root*Trie}funcConstructor()FileSystem{root:=newTrie()returnFileSystem{root}}func(this*FileSystem)Ls(pathstring)[]string{varans[]stringnode:=this.root.search(path)ifnode==nil{returnans}ifnode.isFile{ans=append(ans,node.name)returnans}forv:=rangenode.children{ans=append(ans,v)}sort.Strings(ans)returnans}func(this*FileSystem)Mkdir(pathstring){this.root.insert(path,false)}func(this*FileSystem)AddContentToFile(filePathstring,contentstring){node:=this.root.insert(filePath,true)node.content.WriteString(content)}func(this*FileSystem)ReadContentFromFile(filePathstring)string{node:=this.root.search(filePath)returnnode.content.String()}/** * Your FileSystem object will be instantiated and called as such: * obj := Constructor(); * param_1 := obj.Ls(path); * obj.Mkdir(path); * obj.AddContentToFile(filePath,content); * param_4 := obj.ReadContentFromFile(filePath); */