Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
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.
"/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 * 1042 <= folder[i].length <= 100folder[i] contains only lowercase letters and '/'.folder[i] always starts with the character '/'.Problem summary: 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.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Trie
["/a","/a/b","/c/d","/c/d/e","/c/f"]
["/a","/a/b/c","/a/b/d"]
["/a/b/c","/a/b/ca","/a/b/d"]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1233: Remove Sub-Folders from the Filesystem
class Solution {
public List<String> removeSubfolders(String[] folder) {
Arrays.sort(folder);
List<String> ans = new ArrayList<>();
ans.add(folder[0]);
for (int i = 1; i < folder.length; ++i) {
int m = ans.get(ans.size() - 1).length();
int n = folder[i].length();
if (m >= n
|| !(ans.get(ans.size() - 1).equals(folder[i].substring(0, m))
&& folder[i].charAt(m) == '/')) {
ans.add(folder[i]);
}
}
return ans;
}
}
// Accepted solution for LeetCode #1233: Remove Sub-Folders from the Filesystem
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
}
# Accepted solution for LeetCode #1233: Remove Sub-Folders from the Filesystem
class Solution:
def removeSubfolders(self, folder: List[str]) -> List[str]:
folder.sort()
ans = [folder[0]]
for f in folder[1:]:
m, n = len(ans[-1]), len(f)
if m >= n or not (ans[-1] == f[:m] and f[m] == '/'):
ans.append(f)
return ans
// Accepted solution for LeetCode #1233: Remove Sub-Folders from the Filesystem
struct Solution;
use std::collections::HashSet;
impl Solution {
fn remove_subfolders(folder: Vec<String>) -> Vec<String> {
let mut hs: HashSet<String> = HashSet::new();
for s in folder {
hs.insert(s);
}
let mut res = vec![];
for s in &hs {
if !Self::is_subfolder(s, &hs) {
res.push(s.clone());
}
}
res
}
fn is_subfolder(s: &str, hs: &HashSet<String>) -> bool {
let n = s.len();
for i in 0..n {
if &s[i..=i] == "/" {
if hs.contains(&s[0..i]) {
return true;
}
}
}
false
}
}
#[test]
fn test() {
let folder = vec_string!["/a", "/a/b", "/c/d", "/c/d/e", "/c/f"];
let mut res = vec_string!["/a", "/c/d", "/c/f"];
let mut ans = Solution::remove_subfolders(folder);
ans.sort();
res.sort();
assert_eq!(ans, res);
let folder = vec_string!["/a", "/a/b/c", "/a/b/d"];
let mut res = vec_string!["/a"];
let mut ans = Solution::remove_subfolders(folder);
ans.sort();
res.sort();
assert_eq!(ans, res);
let folder = vec_string!["/a/b/c", "/a/b/ca", "/a/b/d"];
let mut res = vec_string!["/a/b/c", "/a/b/ca", "/a/b/d"];
let mut ans = Solution::remove_subfolders(folder);
ans.sort();
res.sort();
assert_eq!(ans, res);
}
// Accepted solution for LeetCode #1233: Remove Sub-Folders from the Filesystem
function removeSubfolders(folder: string[]): string[] {
let s = folder[1];
return folder.sort().filter(x => !x.startsWith(s + '/') && (s = x));
}
Use this to step through a reusable interview workflow for this problem.
Store all N words in a hash set. Each insert/lookup hashes the entire word of length L, giving O(L) per operation. Prefix queries require checking every stored word against the prefix — O(N × L) per prefix search. Space is O(N × L) for storing all characters.
Each operation (insert, search, prefix) takes O(L) time where L is the word length — one node visited per character. Total space is bounded by the sum of all stored word lengths. Tries win over hash sets when you need prefix matching: O(L) prefix search vs. checking every stored word.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.