算法刷题打卡第84天:删除子文件夹

删除子文件夹

难度:中等

你是一位系统管理员,手里有一份文件夹列表 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"]

排序

思路:

我们可以将字符串数组 folder \textit{folder} folder按照字典序进行排序。在排序完成后,对于每一个 folder [ i ] \textit{folder}[i] folder[i],如果 folder [ i − 1 ] \textit{folder}[i-1] folder[i1] 恰好是它的前缀,并且 folder [ i ] \textit{folder}[i] folder[i] 第一个多出的字符是 / \text{/} /,那么我们就可以把 folder [ i ] \textit{folder}[i] folder[i] 删除。

注意当 folder [ i ] \textit{folder}[i] folder[i] 被删除后,后续的所有字符串都需要向前移动一个位置。例如
[“/a”,“/a/b”,“/a/c”] \text{[``/a'',``/a/b'',``/a/c'']} [“/a”,“/a/b”,“/a/c”]中, “/a/b” \text{``/a/b''} “/a/b” 被删除后,数组会变为 [“/a”,“/a/c”] \text{[``/a'',``/a/c'']} [“/a”,“/a/c”] “/a/c” \text{``/a/c''} “/a/c”也会被删除。

这样做的必要性是显然的,因为如果上述条件满足,就说明 folder [ i ] \textit{folder}[i] folder[i] folder [ i − 1 ] \textit{folder}[i-1] folder[i1] 的子文件夹。对于充分性,我们可以使用反证法:

假设 folder [ i ] \textit{folder}[i] folder[i] 是某个 folder [ j ]   ( j ≠ i − 1 ) \textit{folder}[j]~(j \neq i-1) folder[j] (j=i1) 的子文件夹但不是 folder [ i − 1 ] \textit{folder}[i-1] folder[i1] 的子文件夹,那么在排序后, folder [ j ] \textit{folder}[j] folder[j] 一定出现在 folder [ i ] \textit{folder}[i] folder[i] 的前面,也就是有 j < i j < i j<i。如果有多个满足要求的 j j j,我们选择最早出现的那个。这样就保证了 folder [ j ] \textit{folder}[j] folder[j] 本身不会是其它文件夹的子文件夹。

由于 “/” \text{``/''} “/” 的字典序小于所有的小写字母,并且 folder [ i ] \textit{folder}[i] folder[i] 是由 folder [ j ] \textit{folder}[j] folder[j] 加上 “/” \text{``/''} “/” 再加上后续字符组成,因此在 folder [ i ] \textit{folder}[i] folder[i] folder [ j ] \textit{folder}[j] folder[j] 之间的所有字符串也都一定是由
folder [ j ] \textit{folder}[j] folder[j] 加上 “/” \text{``/''} “/” 再加上后续字符组成。这些字符串都是 folder [ i ] \textit{folder}[i] folder[i] 的子文件夹,它们会依次被删除。当遍历到 folder [ i ] \textit{folder}[i] folder[i] 时,它的上一个元素恰好是 folder [ j ] \textit{folder}[j] folder[j],因此它一定会被删除。

复杂度分析:

  • 时间复杂度: O ( n l ⋅ log ⁡ n ) O(nl \cdot \log n) O(nllogn),其中 n n n l l l 分别是数组 folder \textit{folder} folder 的长度和文件夹的平均长度。 O ( n l ⋅ log ⁡ n ) O(nl \cdot \log n) O(nllogn) 为排序需要的时间,后续构造答案需要的时间为 O ( n l ) O(nl) O(nl),在渐进意义下小于前者。
  • 空间复杂度: O ( l ) O(l) O(l)。在构造答案比较前缀时,我们使用了字符串的截取子串操作,因此需要 O ( l ) O(l) O(l) 的临时空间。我们也可以使用一个递增的指针依次对两个字符串的每个相同位置进行比较,省去这一部分的空间,使得空间复杂度降低至排序需要的栈空间 O ( log ⁡ n ) O(\log n) O(logn)。但空间优化并不是本题的重点,因此上述的代码中仍然采用空间复杂度为 O ( l ) O(l) O(l) 的写法。注意这里不计入返回值占用的空间。
class Solution:
    def removeSubfolders(self, folder: List[str]) -> List[str]:
        folder.sort()
        res = [folder[0]]
        for i in range(1, len(folder)):
            if folder[i][:len(res[-1]) + 1] != res[-1] + '/':
                res.append(folder[i])
        return res

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-sub-folders-from-the-filesystem

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏秃然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值