423/670

423. Design In-Memory File System

Hard

Build a class FileSystem that keeps an entire file hierarchy in memory. Paths are Unix-style absolute strings such as /a/b/c: they always start with /, never end with one, and the root directory by itself is written /. Implement four operations:

  • ls(path) — if path names a file, return a list holding just that file's name; if it names a directory, return the names of everything directly inside it (files and subdirectories together), sorted lexicographically.
  • mkdir(path) — create the directory path, silently creating every missing intermediate directory along the way.
  • addContentToFile(path, content) — if no file exists at path, create it holding content (the parent directory already exists); otherwise append content to the existing data.
  • readContentFromFile(path) — return the file's accumulated content.

A scripted sequence of operations drives your class from stdin; the harness prints one line per ls and one line per read. (Starter code uses each language's naming style for the four methods.)

Example 1:

Input: mkdir("/a/b/c") · ls("/") · ls("/a/b/c") · addContentToFile("/a/b/c/d", "hello") · readContentFromFile("/a/b/c/d") · ls("/a/b/c") · ls("/a")

Output: ls: ["a"], [] · read: "hello" · ls: ["d"], ["b"]

Explanation: mkdir builds a, b, and c in one call, so ls / shows a. The fresh directory /a/b/c lists as an empty line until the file d is added. Reading d returns hello, and ls /a shows its lone subdirectory b.

Example 2:

Input: addContentToFile("/notes", "abc") · addContentToFile("/notes", "def") · readContentFromFile("/notes") · mkdir("/music") · ls("/")

Output: read: "abcdef" · ls: ["music", "notes"]

Explanation: The second add appends, so the file holds abcdef. Listing the root shows both entries sorted: music before notes.

Constraints:

  • 1 ≤ q ≤ 10⁴ operations
  • Path components and file content consist of lowercase English letters only; content is a single non-empty token
  • 2 ≤ path.length ≤ 100 for every path except the root "/"
  • read is only called on existing files, and ls only on existing paths; add's parent directory always exists

Hints:

A file system IS a tree. Give every node a name → child map; a path walk is just a chain of map lookups on the split path components.

One node type can serve both roles: children map + an is-file flag + a content buffer. ls on a directory returns its children's names sorted; ls on a file returns the last path component.

Watch the root: splitting "/" on '/' yields empty pieces. Special-case path == "/" (or filter empty components) so every operation can share one walk helper that optionally creates missing nodes.

▶ Run checks these sample cases. Submit also runs hidden edge cases.

Input: mkdir("/a/b/c") · ls("/") · ls("/a/b/c") · addContentToFile("/a/b/c/d", "hello") · readContentFromFile("/a/b/c/d") · ls("/a/b/c") · ls("/a")

Expected output: ls: ["a"], [] · read: "hello" · ls: ["d"], ["b"]