leetcode 1233. 删除子文件夹

106 阅读2分钟

1. 题目与解析

你是一位系统管理员,手里有一份文件夹列表 folder,你的任务是要删除该列表中的所有 子文件夹,并以 任意顺序 返回剩下的文件夹。

如果文件夹 folder[i] 位于另一个文件夹 folder[j] 下,那么 folder[i] 就是 folder[j] 的 子文件夹 。

文件夹的「路径」是由一个或多个按以下格式串联形成的字符串:'/' 后跟一个或者多个小写英文字母。

  • 例如,"/leetcode" 和 "/leetcode/problems" 都是有效的路径,而空字符串和 "/" 不是。

输入: folder = ["/a","/a/b","/c/d","/c/d/e","/c/f"]

输出: ["/a","/c/d","/c/f"]

解释: "/a/b" 是 "/a" 的子文件夹,而 "/c/d/e" 是 "/c/d" 的子文件夹。

输入: folder = ["/a","/a/b/c","/a/b/d"]

输出: ["/a"]

解释: 文件夹 "/a/b/c" 和 "/a/b/d" 都会被删除,因为它们都是 "/a" 的子文件夹。

输入: folder = ["/a/b/c","/a/b/ca","/a/b/d"]

输出: ["/a/b/c","/a/b/ca","/a/b/d"]

层级信息的统计,很容易让我们想到要使用字典树的数据结构来解决问题。

让我们来梳理一下题目的要求,先确定我们建立字典树结点要使用哪些数据结构:

  • 首先,我们要维护的是所有的父文件路径,需要注意的是,当我们移动到文件的过程中路过的文件夹并不是我们统计的范围,我们答案只输出重点文件路径,即树中的叶子结点,为了方便区分,我们可以在节点中增加isLeaf的标记位;
  • 另外,在查询某一节点是否有对应的叶子结点时,我们肯定希望能更快速的完成查询过程,因此,使用字典的结构存储叶子结点就能使查询效率更优化;
  • 最后,再使用一位存储当前节点的名字,另外还可以按照需求添加其他信息。

有了节点的数据结构,下面就要树立字典树建立的过程:

  • 设置一个flg节点;
  • 对于某一个file路径,从flg开始遍历,如果中途遇见了isLeaf的节点,就停止这一过程;
  • 没有isLeaf节点时,如果已存在子节点,就直接进入,没有的话就新建并且进入;
  • 将file对应的叶子节点标记为isLeaf。

之后使用dfs遍历整棵树,输出所有到叶子结点的路径即可。

2. 题解

class Solution {
    List<String> ans = new ArrayList<>();

    public List<String> removeSubfolders(String[] folder) {
        Node flg = new Node(" ");
        flg.isFlg = true;
        out: for (String f: folder) {
            String[] files = f.split("/");
            Node nextNode = flg;
            for (String file: files) {  
                if (file == "") {continue;}   
                
                if (nextNode.nextNodes.containsKey(file)) {
                    nextNode = nextNode.nextNodes.get(file);
                } else {
                    nextNode.nextNodes.put(file, new Node(file));
                    nextNode = nextNode.nextNodes.get(file);
                }

                if (nextNode.isLeaf) {
                    continue out;
                }                
            }
            nextNode.isLeaf = true;
        }
       
        dfs(flg, "");
        return ans;
    }

    void dfs(Node node, String s) {
        if (!node.isFlg) {
            s += "/" + node.nodeName;
        }
        if (node.isLeaf) {
            ans.add(s);
        } else {
            for (Map.Entry<String, Node> e: node.nextNodes.entrySet()) {
                dfs(e.getValue(), s);
            }
        }
    }
}


class Node {
    String nodeName;
    boolean isLeaf, isFlg;
    Map<String, Node> nextNodes;

    public Node(String s) {
        nodeName = s;
        nextNodes = new HashMap<>();
        isLeaf = false;
    }

}