2 minute read

Problem Statement

problem

Brute Force [Accepted]

class Solution:
    def removeSubfolders(self, folder: List[str]) -> List[str]:
        folder_set = set()
        for f in sorted(folder):
            for s in folder_set:
                if f.startswith(s) and len(f) > len(s):
                    index = len(s)
                    if f[index] == '/':
                        break
            else:
                folder_set.add(f)
        return list(folder_set)
  • time: O(n log n)
  • space: O(n)

Other Brute Force [Accepted]

class Solution:
    def removeSubfolders(self, folder: List[str]) -> List[str]:
        folder_set = set()
        queue = deque(sorted(folder))
        while queue:
            f = queue.popleft()
            folder_set.add(f)
            n = len(queue)
            for _ in range(n):
                s = queue.popleft()
                if s.startswith(f) and len(s) > len(f) and s[len(f)] == '/':
                    continue
                queue.append(s)
        return list(folder_set)

Editorial

Approach 1: Using Set

class Solution:
    def removeSubfolders(self, folder) -> list[str]:
        # Create a set to store all folder paths for fast lookup
        folder_set = set(folder)
        result = []

        # Iterate through each folder to check if it's a sub-folder
        for f in folder:
            is_sub_folder = False
            prefix = f

            # Check all prefixes of the current folder path
            while not prefix == "":
                pos = prefix.rfind("/")
                if pos == -1:
                    break

                # Reduce the prefix to its parent folder
                prefix = prefix[0:pos]

                # If the parent folder exists in the set, mark as sub-folder
                if prefix in folder_set:
                    is_sub_folder = True
                    break

            # If not a sub-folder, add it to the result
            if not is_sub_folder:
                result.append(f)
        return result

Approach 2: Using Sorting

class Solution:
    def removeSubfolders(self, folder):
        # Sort the folders alphabetically
        folder.sort()

        # Initialize the result list and add the first folder
        result = [folder[0]]

        # Iterate through each folder and check if it's a sub-folder of the last added folder in the result
        for i in range(1, len(folder)):
            last_folder = result[-1]
            last_folder += "/"

            # Check if the current folder starts with the last added folder path
            if not folder[i].startswith(last_folder):
                result.append(folder[i])

        # Return the result containing only non-sub-folders
        return result

Approach 3: Using Trie

class Solution:

    class TrieNode:
        def __init__(self):
            self.is_end_of_folder = False
            self.children = {}

    def __init__(self):
        self.root = self.TrieNode()

    def removeSubfolders(self, folder):
        # Build Trie from folder paths
        for path in folder:
            current_node = self.root
            folders = path.split("/")

            for folder_name in folders:
                if folder_name == "":
                    continue

                # Create new node if it doesn't exist
                if folder_name not in current_node.children:
                    current_node.children[folder_name] = self.TrieNode()
                current_node = current_node.children[folder_name]

            # Mark the end of the folder path
            current_node.is_end_of_folder = True

        # Check each path for subfolders
        result = []
        for path in folder:
            current_node = self.root
            folders = path.split("/")
            is_subfolder = False

            for i, folder_name in enumerate(folders):
                if folder_name == "":
                    continue
                next_node = current_node.children[folder_name]
                # Check if the current folder path is a subfolder of an existing folder
                if next_node.is_end_of_folder and i != len(folders) - 1:
                    is_subfolder = True
                    break  # Found a subfolder
                current_node = next_node

            # If not a subfolder, add to the result
            if not is_subfolder:
                result.append(path)

        return result