PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates a software engineer's ability to design and implement an in-memory file system, testing data structure selection, path parsing, and collision-resolution logic. It assesses practical object-oriented design skills and edge-case handling, making it a common coding interview problem for roles requiring systems-level thinking.

  • medium
  • Harvey
  • Coding & Algorithms
  • Software Engineer

In-Memory File System: Create, Track Duplicates, and List

Company: Harvey

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Onsite

# In-Memory File System: Create, Track Duplicates, and List Implement an in-memory file system that supports creating files and folders and listing the contents of a folder. The system must automatically resolve file-name collisions by appending a numbered suffix, similar to how a desktop operating system renames a duplicate download. ## Operations to support Implement a class `FileSystem` with the following methods: 1. `create_folder(path: str) -> str` Create a folder at the given absolute path. The parent folder must already exist. Return the path of the created folder. 2. `create_file(path: str) -> str` Create a file at the given absolute path. The parent folder must already exist. If a file with the **same name** already exists in the same parent folder, do **not** overwrite it — instead create the file under a de-duplicated name and return the **actual** path used. 3. `list_folder(path: str) -> list[str]` Return the names (not full paths) of the immediate children (files and folders) inside the folder at `path`, sorted in ascending lexicographic order. ## Path format - Paths are absolute and `/`-separated, e.g. `/docs/report.txt`. - The root folder `/` always exists and never needs to be created. - A file name may contain a single extension, e.g. `a.txt`. Names without a `.` (such as a folder name, or a file `README`) have no extension. ## Duplicate-naming rule When `create_file` is asked to create a name that already exists as a **file** in the target folder, append ` (n)` before the extension, choosing the **smallest positive integer** `n` (starting at 1) such that the resulting name does not already exist in that folder. - The base part is everything before the **last** `.`; the extension is the `.` and everything after it. A name with no `.` has an empty extension. - The inserted suffix is a single space, an opening parenthesis, the number, and a closing parenthesis — placed immediately before the extension. Examples within one folder: - Existing: `a.txt`. Create `a.txt` → returns name `a (1).txt`. - Existing: `a.txt`, `a (1).txt`. Create `a.txt` → returns name `a (2).txt`. - Existing: `notes` (no extension). Create `notes` → returns name `notes (1)`. - A name like `a (1).txt` that is created directly (no existing collision) is stored verbatim as `a (1).txt` and is **not** further renamed. A folder name never triggers de-duplication: `create_folder` on an existing folder path, or where the name collides with an existing child, should be treated as an error (see below). De-duplication applies **only** to `create_file`. ## Error conditions A method should raise an error (or return a sentinel your harness checks — follow the harness's stub) when: - The parent folder of the target path does not exist. - `create_file` / `create_folder` targets a parent path that exists but is a **file**, not a folder. - `create_folder` targets a path whose name already exists in the parent as either a file or a folder. - `list_folder` is called on a path that does not exist or is a file. ## Constraints - Total number of operations across a session: up to $10^5$. - Path length: up to $300$ characters. - Names consist of letters, digits, spaces, `.`, `(`, and `)`. ## Example session ```text create_folder("/docs") -> "/docs" create_file("/docs/a.txt") -> "/docs/a.txt" create_file("/docs/a.txt") -> "/docs/a (1).txt" create_file("/docs/a.txt") -> "/docs/a (2).txt" create_folder("/docs/imgs") -> "/docs/imgs" list_folder("/docs") -> ["a (1).txt", "a (2).txt", "a.txt", "imgs"] list_folder("/") -> ["docs"] ```

Quick Answer: This question evaluates a software engineer's ability to design and implement an in-memory file system, testing data structure selection, path parsing, and collision-resolution logic. It assesses practical object-oriented design skills and edge-case handling, making it a common coding interview problem for roles requiring systems-level thinking.

Implement an in-memory file system that supports creating files and folders and listing the contents of a folder. The system must automatically resolve file-name collisions by appending a numbered suffix, similar to how a desktop OS renames a duplicate download. You are given an ordered list of operations to replay. Each operation is a pair `[op, path]` where `op` is one of: - `"create_folder"` — create a folder at the absolute `path`. The parent folder must already exist and must be a folder. Return the path of the created folder. - `"create_file"` — create a file at the absolute `path`. The parent folder must already exist and must be a folder. If a **file** with the same name already exists in the same parent folder, do **not** overwrite it; instead create the file under a de-duplicated name and return the **actual** path used. - `"list_folder"` — return the names (not full paths) of the immediate children inside the folder at `path`, sorted ascending lexicographically. Return one result per operation, in order: the resulting path string for `create_folder`/`create_file`, the sorted list of child names for `list_folder`, and the sentinel `"ERROR"` for any operation that violates a rule below. **Path format.** Paths are absolute and `/`-separated, e.g. `/docs/report.txt`. The root folder `/` always exists and never needs to be created. A name may contain a single extension (the `.` and everything after the **last** `.`); a name with no `.` has an empty extension. **Duplicate-naming rule (create_file only).** When the target name already exists as a file in the folder, append ` (n)` immediately before the extension, choosing the smallest positive integer `n` (starting at 1) so the result does not already exist. Examples within one folder: existing `a.txt`, create `a.txt` → `a (1).txt`; existing `a.txt` and `a (1).txt`, create `a.txt` → `a (2).txt`; existing `notes` (no ext), create `notes` → `notes (1)`. A name like `a (1).txt` created with no collision is stored verbatim. De-duplication never applies to `create_folder`. **Error conditions** (yield `"ERROR"`): parent folder of the target does not exist; the parent path exists but is a file; `create_folder` targets a name that already exists in the parent as either a file or a folder; `list_folder` targets a path that does not exist or is a file.

Constraints

  • Total number of operations across a session: up to 10^5.
  • Path length: up to 300 characters.
  • Names consist of letters, digits, spaces, '.', '(', and ')'.
  • Paths are absolute and '/'-separated; root '/' always exists.
  • An extension is the last '.' and everything after it; a name with no '.' has an empty extension.
  • De-duplication applies only to create_file, never to create_folder.

Examples

Input: ([('create_folder', '/docs'), ('create_file', '/docs/a.txt'), ('create_file', '/docs/a.txt'), ('create_file', '/docs/a.txt'), ('create_folder', '/docs/imgs'), ('list_folder', '/docs'), ('list_folder', '/')],)

Expected Output: ['/docs', '/docs/a.txt', '/docs/a (1).txt', '/docs/a (2).txt', '/docs/imgs', ['a (1).txt', 'a (2).txt', 'a.txt', 'imgs'], ['docs']]

Explanation: The canonical session: repeated create_file on a.txt yields a (1).txt then a (2).txt; list_folder('/docs') returns the four children sorted lexicographically; list_folder('/') returns just 'docs'.

Input: ([('create_folder', '/x'), ('create_file', '/x/notes'), ('create_file', '/x/notes'), ('list_folder', '/x')],)

Expected Output: ['/x', '/x/notes', '/x/notes (1)', ['notes', 'notes (1)']]

Explanation: A name with no extension: 'notes' de-dups to 'notes (1)' with the suffix appended to the end (empty extension).

Input: ([('create_file', '/missing/a.txt'), ('create_folder', '/a/b'), ('list_folder', '/nope')],)

Expected Output: ['ERROR', 'ERROR', 'ERROR']

Explanation: Each operation targets a parent folder that does not exist, so each yields ERROR.

Input: ([('create_file', '/f.txt'), ('create_folder', '/f.txt/sub'), ('create_file', '/f.txt/g.txt'), ('list_folder', '/f.txt')],)

Expected Output: ['/f.txt', 'ERROR', 'ERROR', 'ERROR']

Explanation: After creating the file /f.txt, treating it as a parent folder (create under it, or list it) is invalid because it is a file, not a folder.

Input: ([('create_folder', '/d'), ('create_folder', '/d'), ('create_file', '/d'), ('list_folder', '/d')],)

Expected Output: ['/d', 'ERROR', '/d (1)', []]

Explanation: create_folder on an existing name errors; create_file with the same base name 'd' does NOT error — it de-dups to '/d (1)' (a sibling file), leaving folder /d empty.

Input: ([('create_file', '/a (1).txt'), ('create_file', '/a.txt'), ('create_file', '/a.txt'), ('list_folder', '/')],)

Expected Output: ['/a (1).txt', '/a.txt', '/a (2).txt', ['a (1).txt', 'a (2).txt', 'a.txt']]

Explanation: 'a (1).txt' is created verbatim (no collision). Later, the second 'a.txt' must skip the already-taken 'a (1).txt' and become 'a (2).txt'.

Input: ([('list_folder', '/')],)

Expected Output: [[]]

Explanation: Edge case: listing the empty root returns an empty list.

Input: ([('create_folder', '/a'), ('create_folder', '/a/b'), ('create_file', '/a/b/c.tar.gz'), ('create_file', '/a/b/c.tar.gz'), ('list_folder', '/a/b')],)

Expected Output: ['/a', '/a/b', '/a/b/c.tar.gz', '/a/b/c.tar (1).gz', ['c.tar (1).gz', 'c.tar.gz']]

Explanation: Multi-dot name: the extension is the LAST '.' onward ('.gz'), so the base is 'c.tar' and the de-dup suffix lands before '.gz' → 'c.tar (1).gz'.

Hints

  1. Model the file system as a tree (trie) of nodes keyed by child name; each node knows whether it is a directory and holds a map of children. The root '/' is pre-created.
  2. Split each path into its parent components and the final name. Resolve the parent by walking from root; if any step is missing or hits a file, the operation is an error.
  3. For de-duplication, split the name into base (before the LAST '.') and extension (the '.' onward). Try 'base (1)ext', 'base (2)ext', ... until you find a name not already present in the parent's children.
  4. create_folder errors if the name already exists as ANY child (file or folder). create_file never errors on a name clash — it renames instead. Sort children lexicographically for list_folder.
Last updated: Jun 24, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Design an In-Memory Spreadsheet Engine - Harvey (hard)
  • Implement a Spreadsheet With Formulas - Harvey (medium)
  • Implement Spreadsheet Cell Updates - Harvey (hard)
  • Evaluate Symbol Expressions - Harvey (medium)
  • Implement a Cursor-Based Text Editor - Harvey (medium)