1233. 删除子文件夹
大约 3 分钟
1233. 删除子文件夹
题目描述
你是一位系统管理员,手里有一份文件夹列表 folder
,你的任务是要删除该列表中的所有 子文件夹,并以 任意顺序 返回剩下的文件夹。
如果文件夹 folder[i]
位于另一个文件夹 folder[j]
下,那么 folder[i]
就是 folder[j]
的 子文件夹 。
文件夹的「路径」是由一个或多个按以下格式串联形成的字符串:'/' 后跟一个或者多个小写英文字母。
- 例如,
"/leetcode"
和"/leetcode/problems"
都是有效的路径,而空字符串和"/"
不是。
示例 1:
输入:folder = ["/a","/a/b","/c/d","/c/d/e","/c/f"]
输出:["/a","/c/d","/c/f"]
解释:"/a/b" 是 "/a" 的子文件夹,而 "/c/d/e" 是 "/c/d" 的子文件夹。
示例 2:
输入:folder = ["/a","/a/b/c","/a/b/d"]
输出:["/a"]
解释:文件夹 "/a/b/c" 和 "/a/b/d" 都会被删除,因为它们都是 "/a" 的子文件夹。
示例 3:
输入: folder = ["/a/b/c","/a/b/ca","/a/b/d"]
输出: ["/a/b/c","/a/b/ca","/a/b/d"]
提示:
1 <= folder.length <= 4 * 104
2 <= folder[i].length <= 100
folder[i]
只包含小写字母和'/'
folder[i]
总是以字符'/'
起始- 每个文件夹名都是 唯一 的
思路
时间复杂的分析
根据提示中的数据,folder的数量在104数量级,每个folder[i]小于100,则需要思考时间复杂为O(n)的解法,
n为folder.length*folder[i].length。
解题思路
朴素的解法是两层循环,即对每一个folder[i]进行0到folder.length的遍历,寻找其前缀是否存在,存在就跳过,不存在则将其加入结果中。
因为是求前缀是否存在,我们可以通过排序来减少全部遍历。
将folder进行字典序的排序,我们可以发现,如果当前字符串包含了前一个字符串且前缀和前一个字符串相同,那我们就可以把当前字符串去掉,继续下一个循环。如果不相同,我们则将当前字符串加入答案,并且更新前一个字符串为当前字符串并继续循环。
另外一种思路,求是否存在前缀,字典树是比较合适的方法。时间复杂度也是合适的。
数据结构选择
如果采用排序的方式,则只需要一个List作为答案进行返回,不需要额外的数据结构。
如果采用字典树的方式,则需要进行字典树的生成。
题解
//排序的方式
class Solution {
public List<String> removeSubfolders(String[] folder) {
Arrays.sort(folder); //排序
int n=folder.length;
List<String> ans=new ArrayList<>();
int idx=0;
ans.add(folder[0]);
for(int i=1;i<n;i++){
int xn=folder[i].length(),x3=xn-1;
int yn=folder[idx].length();
while(x3>0){
if(folder[i].charAt(x3)=='/'){
break;
}
x3--;
} //获取0到最后一个‘/’字符间的子串
if(folder[i].substring(0,x3).contans(folder[idx]) &&
yn<xn && folder[idx].equals(folder[i].substring(0,yn)) //判断子串是否包含前一个字符串,同时前缀相同
){
continue;
}
else{
ans.add(folder[i]);
idx=i;
}
}
return ans;
}
}
// 字典树的方式,来自力扣题解
class Solution {
public List<String> removeSubfolders(String[] folder) {
Trie root = new Trie();
for (int i = 0; i < folder.length; ++i) {
List<String> path = split(folder[i]);
Trie cur = root;
for (String name : path) {
cur.children.putIfAbsent(name, new Trie());
cur = cur.children.get(name);
}
cur.ref = i;
}
List<String> ans = new ArrayList<String>();
dfs(folder, ans, root);
return ans;
}
public List<String> split(String s) {
List<String> ret = new ArrayList<String>();
StringBuilder cur = new StringBuilder();
for (int i = 0; i < s.length(); ++i) {
char ch = s.charAt(i);
if (ch == '/') {
ret.add(cur.toString());
cur.setLength(0);
} else {
cur.append(ch);
}
}
ret.add(cur.toString());
return ret;
}
public void dfs(String[] folder, List<String> ans, Trie cur) {
if (cur.ref != -1) {
ans.add(folder[cur.ref]);
return;
}
for (Trie child : cur.children.values()) {
dfs(folder, ans, child);
}
}
}
class Trie {
int ref;
Map<String, Trie> children;
public Trie() {
ref = -1;
children = new HashMap<String, Trie>();
}
}