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 01:
-
C++
-
Python
#include <bits/stdc++.h> using namespace std; class Solution { public: vector<string> removeSubfolders(vector<string>& folderPaths) { vector<string> result; string previousFolder; ranges::sort(folderPaths); for (const string& currentFolder : folderPaths) { if (!previousFolder.empty() && currentFolder.find(previousFolder) == 0 && currentFolder[previousFolder.length()] == '/') continue; result.push_back(currentFolder); previousFolder = currentFolder; } return result; } };
class Solution: def removeSubfolders(self, folderPaths: list[str]) -> list[str]: result = [] previousFolder = "" folderPaths.sort() for currentFolder in folderPaths: if previousFolder and currentFolder.startswith(previousFolder) and currentFolder[len(previousFolder)] == '/': continue result.append(currentFolder) previousFolder = currentFolder return result
Time Complexity
- Sorting:
The
folderPaths
vector is sorted lexicographically usingranges::sort
, which takes \(O(n \log n)\), wheren
is the total number of folder paths. - Looping through folder paths:
After sorting, the algorithm iterates through each folder path, checking whether the current folder starts with the previous folder as a prefix. This comparison step takes \(O(L)\), where
L
is the average length of the folder path. Thus, the loop runs in \(O(n \cdot L)\), where \(L\) is the average string length, andn
is the number of folder paths. - Overall Time Complexity:
The overall time complexity is \(O(n \log n + n \cdot L)\). Since the \(n \log n\) term typically dominates, the final complexity is \(O(n \log n)\).
Space Complexity
- Sorting:
The sorting operation requires \(O(n)\) additional space for sorting the folder paths in place.
- Result Vector:
The result vector stores all the non-subfolder paths, requiring \(O(n)\) space in the worst case (if no subfolders are removed).
- Overall Space Complexity:
The space complexity is \(O(n + L)\), where
n
is the number of folder paths andL
is the average length of the strings.