Skip to content

Commit a3b6cfc

Browse files
committed
2025-07-19打卡
1 parent f9a1cdf commit a3b6cfc

2 files changed

Lines changed: 92 additions & 2 deletions

File tree

algorithm/数据结构/树形数据结构/Trie树.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Trie:
3030
cur = cur[c]
3131
return True
3232

33-
def startsWith(self, prefix: str) -> bool:
33+
def start_with(self, prefix: str) -> bool:
3434
cur = self.son
3535
for c in prefix:
3636
if c not in cur:
@@ -42,4 +42,5 @@ class Trie:
4242
## 3. 例题
4343

4444
- [LCR 062. 实现 Trie (前缀树)](/leetcode/8-119经典题变种挑战/挑战%2010:前缀树/LCR%20062.%20实现%20Trie%20(前缀树).md)
45-
- [LCR 063. 单词替换](/leetcode/8-119经典题变种挑战/挑战%2010:前缀树/LCR%20063.%20单词替换.md)
45+
- [LCR 063. 单词替换](/leetcode/8-119经典题变种挑战/挑战%2010:前缀树/LCR%20063.%20单词替换.md)
46+
- [1233. 删除子文件夹](/leetcode/4-每日一题/1233.%20删除子文件夹.md)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# [1233. 删除子文件夹](https://leetcode.cn/problems/remove-sub-folders-from-the-filesystem/description/)
2+
3+
> **日期**:2025-07-19
4+
> **所用时间**:10min
5+
6+
## 1. 排序 + 字典树
7+
8+
### 题目分析
9+
10+
本题要求从一组文件夹路径中删除所有子文件夹,只保留每个文件夹的最顶层父文件夹。例如,`/a``/a/b`,只保留 `/a`,因为 `/a/b``/a` 的子文件夹。
11+
12+
### 解题思路
13+
14+
1. **排序**
15+
首先将所有文件夹路径按字典序排序。这样父文件夹总是在子文件夹前面。
16+
17+
2. **字典树(Trie)建模**
18+
用字典树存储每个文件夹路径。每插入一个路径时,如果在插入过程中遇到某个节点已经是终止节点(即之前插入过的父文件夹),说明当前路径是某个父文件夹的子文件夹,直接跳过即可。
19+
20+
3. **去重与收集答案**
21+
只有在插入过程中没有遇到父文件夹终止节点的路径,才加入答案。
22+
23+
### 关键点
24+
25+
- 路径分割时要去掉第一个空字符串(因为 `/a/b``split('/')` 得到 `['', 'a', 'b']`)。
26+
- 字典树节点用 `[is_end, children]` 结构,`is_end` 表示该节点是否为某个文件夹的结尾。
27+
- 由于排序,父文件夹总是先于子文件夹插入,保证了判断的正确性。
28+
29+
### 复杂度分析
30+
31+
- 时间复杂度: $O(n \log n)$
32+
- 空间复杂度: $O(n)$
33+
34+
**Python3**
35+
36+
```python
37+
class Trie:
38+
def __init__(self):
39+
self.son = [False, {}]
40+
41+
def insert(self, word):
42+
is_match = False
43+
cur = self.son
44+
for c in word:
45+
if cur[0]:
46+
is_match = True
47+
if c not in cur[1]:
48+
cur[1][c] = [False, {}]
49+
cur = cur[1][c]
50+
cur[0] = True
51+
return is_match
52+
53+
class Solution:
54+
def removeSubfolders(self, folder: List[str]) -> List[str]:
55+
tree = Trie()
56+
folder.sort()
57+
ans = []
58+
for s in folder:
59+
if not tree.insert(s.split('/')[1:]):
60+
ans.append(s)
61+
return ans
62+
```
63+
64+
## 2. 排序 + 前缀判断
65+
66+
1. **排序**
67+
先对所有文件夹路径排序,父文件夹一定在子文件夹前面。
68+
69+
2. **遍历判断**
70+
用一个结果数组 `ans`,每次判断当前路径 `s` 是否是上一个加入结果的路径 `last` 的子文件夹。判断条件是:`s``last` 开头,且 `s[len(last)] == '/'`,否则就不是子文件夹,可以加入结果。
71+
72+
### 复杂度分析
73+
74+
- 时间复杂度: $O(n \log n)$
75+
- 空间复杂度: $O(n)$
76+
77+
**Python3**
78+
79+
```python
80+
class Solution:
81+
def removeSubfolders(self, folder: List[str]) -> List[str]:
82+
folder.sort()
83+
ans = [folder[0]]
84+
for s in folder[1:]:
85+
last = ans[-1]
86+
if not s.startswith(last) or s[len(last)] != '/':
87+
ans.append(s)
88+
return ans
89+
```

0 commit comments

Comments
 (0)