Talentd
FleetCode
Make and follow sheets.Sign in

Remove Sub-Folders from the Filesystem solution and explanation

MediumArrayDepth-First SearchStringTrie7 min read78.6% acceptanceUpdated 9 Apr 2026
Remove Sub-Folders from the Filesystem - Leetcode 1233 - PythonNeetCodeIO · 19:29 · 13K viewsWatch on YouTube
9 more videos on this problem
  1. Remove Sub-Folders from the Filesystem - Leetcode 1233 - PythonNeetCodeIO · 19:29 · 13K views
  2. Remove Sub-Folders from the Filesystem | 2 Simple Approaches | Leetcode 1233 | codestorywithMIKcodestorywithMIK · 30:19 · 12K views
  3. Remove Sub Folders from the Filesystem | Leetcode 1233Techdose · 20:59 · 2K views
  4. LeetCode 1233. Remove Sub-Folders from the FilesystemHappy Coding · 9:53 · 2K views
  5. REMOVE SUB-FOLDERS FROM FILE SYSTEM | LEETCODE 1233 | PYTHON TRIE SOLUTIONCracking FAANG · 16:24 · 841 views
  6. Daily Leetcode #1936: Jul 19, 2025 - 1233. Remove Sub-Folders from the FilesystemProgramming Live with Larry · 14:09 · 464 views
  7. 1233. Remove Sub-Folders from the Filesystem | Leetcode Daily - PythonLeetcode Daily · 7:49 · 193 views
  8. Remove Sub-Folders from the Filesystem | Leetcode 1233 | String | SortingTech With Anubhav · 16:52 · 176 views
  9. 1233. Remove Sub-Folders from the FilesystemEmgineerSingh · 30:55 · 148 views
  10. Leetcode 1233 | Remove Sub-Folders from the Filesystem | Coded SolutionByteGambit · 5:03 · 126 views

The problem

Given a list of folders folder, return the folders after removing all sub-folders in those folders. You may return the answer in any order.

If a folder[i] is located within another folder[j], it is called a sub-folder of it. A sub-folder of folder[j] must start with folder[j], followed by a "/". For example, "/a/b" is a sub-folder of "/a", but "/b" is not a sub-folder of "/a/b/c".

The format of a path is one or more concatenated strings of the form: '/' followed by one or more lowercase English letters.

  • For example, "/leetcode" and "/leetcode/problems" are valid paths while an empty string and "/" are not.

Example 1:

Input: folder = ["/a","/a/b","/c/d","/c/d/e","/c/f"]
Output: ["/a","/c/d","/c/f"]
Explanation: Folders "/a/b" is a subfolder of "/a" and "/c/d/e" is inside of folder "/c/d" in our filesystem.

Example 2:

Input: folder = ["/a","/a/b/c","/a/b/d"]
Output: ["/a"]
Explanation: Folders "/a/b/c" and "/a/b/d" will be removed because they are subfolders of "/a".

Example 3:

Input: folder = ["/a/b/c","/a/b/ca","/a/b/d"]
Output: ["/a/b/c","/a/b/ca","/a/b/d"]

Constraints:

  • 1 <= folder.length <= 4 * 104
  • 2 <= folder[i].length <= 100
  • folder[i] contains only lowercase letters and '/'.
  • folder[i] always starts with the character '/'.
  • Each folder name is unique.

Approach overview

Problem Overview: You receive a list of folder paths in a filesystem. Some folders may be subfolders of others (for example /a/b is inside /a). The task is to return only the top-level folders and remove every path that is a subfolder of another.

Approach 1: Sorting and Checking Prefix (O(n log n) time, O(1) extra space)

Sort all folder paths lexicographically. Once sorted, subfolders naturally appear right after their parent folder because they share the same prefix. Iterate through the sorted list and keep a folder only if it is not prefixed by the last accepted folder plus /. The key insight is that sorting groups related paths together, which eliminates the need to compare every pair. This approach relies heavily on string prefix comparison and works well for interview settings because it is simple and efficient. The overall time complexity is O(n log n) for sorting plus linear scanning, and space complexity is O(1) aside from the output. This approach mainly uses concepts from Array and String processing.

Approach 2: Using Trie Data Structure (O(T) time, O(T) space)

Insert each folder path into a Trie where each node represents a directory name between slashes. While inserting, stop if you reach a node already marked as a complete folder path. That indicates a parent folder already exists, so the current path is a subfolder and should be ignored. If insertion completes, mark the final node as an end node and discard any deeper children. The key idea is that the Trie naturally models hierarchical filesystem structure. Each traversal step corresponds to moving deeper into directories, making it easy to detect when a parent folder already exists. Time complexity is O(T) where T is the total number of characters across all paths, and space complexity is also O(T) due to storing the Trie nodes. This method highlights structured path processing using Trie and recursive traversal patterns similar to Depth-First Search.

Recommended for interviews: The sorting and prefix check approach is typically what interviewers expect. It demonstrates strong reasoning about lexicographic ordering and efficient scanning. The Trie approach shows deeper understanding of hierarchical data structures and filesystem modeling. Mentioning both approaches signals strong problem-solving breadth.

Approach 1: Approach 1: Sorting and Checking Prefix

The main idea of this approach is to first sort the folders alphabetically. This way, any sub-folder will appear immediately after its parent folder. We can then iterate through the sorted list and check if the current folder is a prefix of the next folder (followed by '/'). If it is not a prefix, we add it to the final result list.

def removeSubfolders(folder):
    folder.sort()
    res = []
    prev = ""
    for f in folder:
        if not f.startswith(prev):
            res.append(f)
            prev = f + "/"
    return res
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Solution {
    public List<String> removeSubfolders(String[] folder) {
        Arrays.sort(folder);
        List<String> res = new ArrayList<>();
        String prev = "";
        for (String f : folder) {
            if (!f.startsWith(prev)) {
                res.add(f);
                prev = f + "/";
            }
        }
        return res;
    }
}
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

vector<string> removeSubfolders(vector<string>& folder) {
    sort(folder.begin(), folder.end());
    vector<string> res;
    string prev = "";
    for (const string& f : folder) {
        if (f.find(prev) != 0) {
            res.push_back(f);
            prev = f + "/";
        }
    }
    return res;
}
function removeSubfolders(folder) {
    folder.sort();
    const res = [];
    let prev = "";
    for (const f of folder) {
        if (!f.startsWith(prev)) {
            res.push(f);
            prev = f + "/";
        }
    }
    return res;
}

This Python solution sorts the folder paths and iterates through them. It maintains a 'prev' variable to store the last added folder to the results, ensuring we only add a folder if it is not a sub-folder of the previous folder in the result list.

Complexity

Time Complexity: O(n log n) due to sorting the list. Space Complexity: O(n) for storing the result list.

Try this approach in the editor

Approach 2: Approach 2: Using Trie Data Structure

In this approach, we use a Trie (or Prefix Tree) to represent the hierarchy of folders. We insert each folder path into the Trie while ensuring to mark the end of any folder. During insertion, if we find that a folder is already marked as the end of a path in the Trie, we ignore any further paths as sub-folders of this path.

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_end = False

class Solution:
    def removeSubfolders(self, folder):
        root = TrieNode()
        for path in sorted(folder):
            node = root
            is_subfolder = False
            for part in path.split('/')[1:]:
                if part not in node.children:
                    node.children[part] = TrieNode()
                node = node.children[part]
                if node.is_end:
                    is_subfolder = True
                    break
            if not is_subfolder:
                node.is_end = True
        res = []
        def dfs(node, path):
            if node.is_end:
                res.append('/' + '/'.join(path))
                return
            for part, child in node.children.items():
                dfs(child, path + [part])
        dfs(root, [])
        return res
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;

class TrieNode {
public:
    unordered_map<string, TrieNode*> children;
    bool isEnd;
    TrieNode() : isEnd(false) {}
};

void insert(TrieNode* root, const string& path) {
    TrieNode* node = root;
    istringstream stream(path);
    string part;
    while (getline(stream, part, '/')) {
        if (part.empty()) continue;
        if (!node->children.count(part))
            node->children[part] = new TrieNode();
        node = node->children[part];
        if (node->isEnd) return;
    }
    node->isEnd = true;
}

void collect(TrieNode* node, string path, vector<string>& result) {
    if (node->isEnd) {
        result.push_back(path);
        return;
    }
    for (auto& [part, child] : node->children) {
        collect(child, path + "/" + part, result);
    }
}

class Solution {
public:
    vector<string> removeSubfolders(vector<string>& folder) {
        sort(folder.begin(), folder.end());
        TrieNode* root = new TrieNode();
        for (const auto& path : folder) {
            insert(root, path);
        }
        vector<string> result;
        collect(root, "", result);
        return result;
    }
};

This Python solution builds a Trie for all folder paths. It only marks paths as ends when they are not sub-folders, thus ignoring deeper sub-folders in the structure.

Complexity

Time Complexity: O(n * l) where n is the number of folders, and l is the average length of the folder paths. Space Complexity: O(n * l) for the Trie.

Try this approach in the editor

Approach 3: Sorting

First, we sort the array folder in lexicographical order, then traverse the array. For the current folder f we are traversing, if its length is greater than or equal to the length of the last folder in the answer array, and its prefix includes the last folder in the answer array plus a /, then f is a subfolder of the last folder in the answer array, and we don't need to add it to the answer array. Otherwise, we add f to the answer array.

After the traversal ends, the folders in the answer array are the answer required by the problem.

The time complexity is O(n times log n times m), and the space complexity is O(m). Where n and m are the length of the array folder and the maximum length of the strings in the array folder, respectively.

function removeSubfolders(folder: string[]): string[] {
    let s = folder[1];
    return folder.sort().filter(x => !x.startsWith(s + '/') && (s = x));
}
func removeSubfolders(folder []string) []string {
	sort.Strings(folder)
	ans := []string{folder[0]}
	for _, f := range folder[1:] {
		m, n := len(ans[len(ans)-1]), len(f)
		if m >= n || !(ans[len(ans)-1] == f[:m] && f[m] == '/') {
			ans = append(ans, f)
		}
	}
	return ans
}
Try this approach in the editor

Approach 4: Trie

We can use a trie to store all the folders in the array folder. Each node of the trie contains a children field, used to store the child nodes of the current node, and a fid field, used to store the index of the folder corresponding to the current node in the array folder.

For each folder f in the array folder, we first split f into several substrings according to /, then start from the root node and add the substrings to the trie in turn. Next, we start from the root node to search the trie. If the fid field of the current node is not -1, it means that the folder corresponding to the current node is a folder in the answer array. We add it to the answer array and return. Otherwise, we recursively search all child nodes of the current node and finally return the answer array.

The time complexity is O(n times m), and the space complexity is O(n times m). Where n and m are the length of the array folder and the maximum length of the strings in the array folder, respectively.

class Trie {
    children: Record<string, Trie>;
    fid: number;

    constructor() {
        this.children = {};
        this.fid = -1;
    }

    insert(i: number, f: string): void {
        let node: Trie = this;
        const ps = f.split('/');
        for (let j = 1; j < ps.length; ++j) {
            const p = ps[j];
            if (!(p in node.children)) {
                node.children[p] = new Trie();
            }
            node = node.children[p];
        }
        node.fid = i;
    }

    search(): number[] {
        const ans: number[] = [];
        const dfs = (root: Trie): void => {
            if (root.fid !== -1) {
                ans.push(root.fid);
                return;
            }
            for (const child of Object.values(root.children)) {
                dfs(child);
            }
        };
        dfs(this);
        return ans;
    }
}

function removeSubfolders(folder: string[]): string[] {
    const trie = new Trie();
    for (let i = 0; i < folder.length; ++i) {
        trie.insert(i, folder[i]);
    }
    return trie.search().map(i => folder[i]);
}
type Trie struct {
	children map[string]*Trie
	fid      int
}

func newTrie() *Trie {
	return &Trie{map[string]*Trie{}, -1}
}

func (this *Trie) insert(fid int, f string) {
	node := this
	ps := strings.Split(f, "/")
	for _, p := range ps[1:] {
		if _, ok := node.children[p]; !ok {
			node.children[p] = newTrie()
		}
		node = node.children[p]
	}
	node.fid = fid
}

func (this *Trie) search() (ans []int) {
	var dfs func(*Trie)
	dfs = func(root *Trie) {
		if root.fid != -1 {
			ans = append(ans, root.fid)
			return
		}
		for _, child := range root.children {
			dfs(child)
		}
	}
	dfs(this)
	return
}

func removeSubfolders(folder []string) (ans []string) {
	trie := newTrie()
	for i, f := range folder {
		trie.insert(i, f)
	}
	for _, i := range trie.search() {
		ans = append(ans, folder[i])
	}
	return
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Approach 1: Sorting and Checking Prefix

Time Complexity: O(n log n) due to sorting the list. Space Complexity: O(n) for storing the result list.

Approach 2: Using Trie Data Structure

Time Complexity: O(n * l) where n is the number of folders, and l is the average length of the folder paths. Space Complexity: O(n * l) for the Trie.

Sorting–
Trie–

Complexity analysis

ApproachTimeSpaceWhen to Use
Sorting + Prefix CheckO(n log n)O(1)Best general solution. Simple implementation and commonly expected in interviews.
Trie Data StructureO(T)O(T)Useful when modeling hierarchical paths or when many shared prefixes exist.

Frequently asked questions

Is Remove Sub-Folders from the Filesystem easy or hard?

The problem is rated Medium because the key insight involves recognizing how lexicographic sorting groups parent folders with their subfolders. Once that observation is made, the implementation becomes straightforward.

Remove Sub-Folders from the Filesystem Python/Java solution

Python, Java, C++, and JavaScript implementations usually follow the same strategy: sort the folder list, iterate through it, and skip paths that start with the previous kept folder plus '/'. Trie implementations are also possible in Python and C++ for demonstrating hierarchical parsing.

How to solve Remove Sub-Folders from the Filesystem in O(n)?

Strict O(n) relative to the number of folders is difficult because sorting is typically required. However, a Trie-based approach processes each character of every path once, giving O(T) complexity where T is the total length of all paths. This effectively behaves like linear time with respect to input size.

What is the best approach for Remove Sub-Folders from the Filesystem?

The sorting and prefix-check approach is considered the best practical solution. Sort the folder paths lexicographically and keep a folder only if it is not prefixed by the previously accepted folder plus '/'. This reduces the problem to a single pass after sorting and runs in O(n log n) time.

Is Remove Sub-Folders from the Filesystem asked at Google/Amazon/Meta?

Filesystem path problems and prefix filtering questions frequently appear in interviews at large companies such as Amazon, Google, and Meta. They test string manipulation, sorting strategies, and hierarchical data structures like tries.

What data structure is used in Remove Sub-Folders from the Filesystem?

The most common solution uses arrays and string prefix comparison after sorting the paths. Another approach uses a Trie to represent folder hierarchy, allowing efficient detection of parent folders during insertion.

What is the time complexity of Remove Sub-Folders from the Filesystem?

The common optimal solution runs in O(n log n) time due to sorting the folder paths, followed by an O(n) scan to filter subfolders. A Trie-based approach can achieve O(T) time where T is the total number of characters across all folder paths.

Comments

Now write it yourselfClose this page and solve Remove Sub-Folders from the Filesystem in the editor, without looking.
Practise Remove Sub-Folders from the Filesystem