题目:
你是一位系统管理员,手里有一份文件夹列表 folder,你的任务是要删除该列表中的所有 子文件夹,并以 任意顺序 返回剩下的文件夹。
如果文件夹 folder[i] 位于另一个文件夹 folder[j] 下,那么 folder[i] 就是 folder[j] 的 子文件夹 。
文件夹的「路径」是由一个或多个按以下格式串联形成的字符串:'/' 后跟一个或者多个小写英文字母。
- 例如,
"/leetcode"和"/leetcode/problems"都是有效的路径,而空字符串和"/"不是。
算法:
方法一:字典树
典型的字典树变形应用。读清楚题意,字典树的叶子可能是多个字符,以及strings.Split("/", "/")会得到两个元素,/左边的空字符和右边的空字符。
func removeSubfolders(folder []string) []string {
tier := NewTier()
// 构造字典树
for i := range folder {
t := tier
items := strings.Split(folder[i],"/")
for _, d := range items[1:] {
if t.Char[d] == nil {
t.Char[d] = NewTier()
}
t = t.Char[d]
}
t.Floder = i
}
ans := make([]string, 0)
var dfs func(t *Tier)
dfs = func(t *Tier) {
if t == nil {
return
}
if t.Floder != -1 {
ans = append(ans, string(folder[t.Floder]))
return
}
for i := range t.Char {
dfs(t.Char[i])
}
}
for i := range tier.Char {
dfs(tier.Char[i])
}
return ans
}
type Tier struct {
Char map[string]*Tier
Floder int
}
func NewTier() *Tier {
return &Tier{
Char: make(map[string]*Tier),
Floder: -1,
}
}
方法二:排序
注意提示,floder中没有重复元素,其实进行了很大的简化。排序之后,父目录在前,先排除必然不是父子关系的目录:len(floder[i - 1]) >= len(floder[i])必然不存在父子关系。
- 如果len(ans[len(ans) - 1]) >= len(floder[i])可以直接加入ans。
- 如果len(ans[len(ans) - 1]) < len(floder[i]),如果floder[i - 1]是floder[i]的前缀,并且floder[i]多出一个"/",则floder[i]是子目录,可以过滤掉。
func removeSubfolders(folder []string) []string {
sort.Strings(folder)
ans := []string{folder[0]}
for i := 1; i < len(folder); i ++ {
n := len(ans)
lastFloderLen := len(ans[n - 1])
curFloderLen := len(folder[i])
if lastFloderLen >= curFloderLen || !(strings.HasPrefix(folder[i], ans[n - 1]) && folder[i][lastFloderLen] == '/') {
ans = append(ans, folder[i])
}
}
return ans
}