#588 Design In-Memory File System
the problem
In plain words
You're writing the storage layer of a small browser-based code editor, and everything lives in memory. Implement FileSystem with four calls. ls(path): for a file, return a list holding just the file's name; for a folder, return the names of everything directly inside it, in alphabetical order. mkdir(path): create that folder, plus any missing folders above it. addContentToFile(filePath, content): create the file if it is new, then append content to it. readContentFromFile(filePath): return everything written to the file so far. Every call is valid: ls and read only ask about paths that exist, mkdir creates a folder that doesn't exist yet, a new file goes into a folder that already exists, and a file and a folder never share a name inside the same folder.
in ls("/"), mkdir("/home/priya/code"), addContentToFile("/home/priya/code/notes", "stack"), addContentToFile("/home/priya/todo", "revise"), ls("/home/priya"), addContentToFile("/home/priya/code/notes", "queue"), readContentFromFile("/home/priya/code/notes"), ls("/home/priya/code/notes"), ls("/")
out [], null, null, null, ["code", "todo"], null, "stackqueue", ["notes"], ["home"]
mkdir created home, priya and code in one call. The second write to notes is appended. ls on a file lists only its own name.
- Paths are absolute: they start with "/" and don't end with "/" (except "/" itself); 1 ≤ path length ≤ 100
- Names use lowercase letters only
- 1 ≤ content length ≤ 50
- At most 300 calls in total
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code right here. Stuck for 20 minutes? Open one hint at a time.
This one is LeetCode Premium. You don't need a subscription: solve it right here. The free alternative linked above is the closest free practice; its label says how close it is.
Solve it in the browser
Design: implement every operation. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternTrie (prefix tree)Class design: state + operations
where this runsUnix-style file systems resolve a path one directory at a time: each directory maps names to i-numbers (Ritchie & Thompson, 1974).
A file system is a tree: every folder maps a child's name to the child. Split the path on / and walk one name at a time — a trie whose letters are whole names. Keep the children in a TreeMap and ls gets its names already sorted.
solutions
From brute force to optimal
Keep every folder path in a set and every file path → content in a map; ls scans all of them for the folder's prefix.
- mkdir: add the path and each of its prefixes to the folder set.
- addContentToFile / read: a HashMap from the full file path to a StringBuilder.
- ls: a file returns its name; otherwise scan every stored path that starts with
path + "/", keep the first name after the prefix, and sort with a TreeSet.
ls compares the prefix with all P stored paths (each up to L characters); the other calls hash one path string.
Every path is stored as a full string, so shared parent names are stored again and again.
// On LeetCode, name this class FileSystem.class FileSystemFlat { private final Set<String> dirs = new HashSet<>(Set.of("/")); // every folder, as a full path private final Map<String, StringBuilder> files = new HashMap<>(); // file path → content public List<String> ls(String path) { if (files.containsKey(path)) return List.of(path.substring(path.lastIndexOf('/') + 1)); String prefix = path.equals("/") ? "/" : path + "/"; TreeSet<String> names = new TreeSet<>(); // sorted, no duplicates List<String> all = new ArrayList<>(dirs); all.addAll(files.keySet()); for (String p : all) { // scans EVERY stored path: O(P · L) if (!p.startsWith(prefix) || p.length() == prefix.length()) continue; String rest = p.substring(prefix.length()); int slash = rest.indexOf('/'); names.add(slash < 0 ? rest : rest.substring(0, slash)); // the first name below path } return new ArrayList<>(names); } public void mkdir(String path) { for (int i = 1; i <= path.length(); i++) { // "/a/b/c" adds /a, /a/b and /a/b/c if (i == path.length() || path.charAt(i) == '/') dirs.add(path.substring(0, i)); } } public void addContentToFile(String filePath, String content) { files.computeIfAbsent(filePath, k -> new StringBuilder()).append(content); } public String readContentFromFile(String filePath) { return files.get(filePath).toString(); }}One node per folder or file; each node maps names to children. Walk the path with split("/").
- walk(path): start at the root; for each non-empty name,
computeIfAbsentthe child and step into it. - mkdir: walk — missing folders get created on the way.
- addContentToFile: walk; if content is null it is a new file, so give it a StringBuilder; append.
- ls: walk; a file returns [its name]; a folder returns
new ArrayList<>(children.keySet()), already sorted. read: walk and return the content.
Each of the d names in the path costs one TreeMap lookup among c siblings; ls then copies the k names it returns.
One node per folder or file, and each name is stored once.
class FileSystem { private static class Node { final TreeMap<String, Node> children = new TreeMap<>(); // name → child, kept sorted for ls StringBuilder content; // null for a folder, text for a file } private final Node root = new Node(); /** Walks from the root, one name at a time, creating missing folders on the way. */ private Node walk(String path) { Node node = root; for (String name : path.split("/")) { // "/a/b" → ["", "a", "b"]; "/" → [] if (name.isEmpty()) continue; node = node.children.computeIfAbsent(name, k -> new Node()); } return node; } public List<String> ls(String path) { Node node = walk(path); if (node.content != null) { // a file lists only its own name return List.of(path.substring(path.lastIndexOf('/') + 1)); } return new ArrayList<>(node.children.keySet()); // TreeMap keys are already sorted } public void mkdir(String path) { walk(path); // creates every missing folder on the path } public void addContentToFile(String filePath, String content) { Node file = walk(filePath); if (file.content == null) file.content = new StringBuilder(); // a new file file.content.append(content); // append, never overwrite } public String readContentFromFile(String filePath) { return walk(filePath).content.toString(); }}Dry run
in the room
How to say it in the interview
talk track
- Clarify: absolute paths only? Can a file and a folder share a name? Must ls be sorted? (Yes, alphabetical.)
- Point out that a flat map makes ls scan everything, then draw the tree: folders are nodes, names are the edges.
- Write walk() once and reuse it in all four methods — that is most of the code.
- Explain the TreeMap choice: sorted ls for O(log c) per step. A HashMap plus a sort inside ls is the alternative when ls is rare.
traps
- Not skipping the empty strings from
split("/")—"/a".split("/")starts with"". - Overwriting a file's content instead of appending to it.
- ls on a file must return a one-element list with the file's name, not an empty list.
- Returning your own
keySet()view — copy it into a new ArrayList.
what they ask next
Follow-ups
Add rm (delete) and mv (move)?
rm: walk to the parent and remove the child's entry — the whole subtree goes with it. mv: unhook the node from its old parent and hang it under the new parent with the new name; nothing is copied.
Wildcards like /logs/*/today?
Walk the fixed part, then DFS through every child where the * is — the same idea as Add and Search Words (LC 211) with '.'.
before you submit
Edge cases to test
- ls("/") on an empty file system returns [].
- ls on a file path returns a one-element list with the file's name.
- Appending twice to the same file joins both contents.
- A file and a folder whose names share a prefix ("a" and "ab") are listed separately, in order.
practise next
Similar problems
- #208Implement Trie (Prefix Tree)Mediumin Tries
- #71Simplify PathMediumin Stacks
- #211Design Add and Search Words Data StructureMediumin Tries