Due to a bug, there are many duplicate folders in a file system. You are given a 2D array paths, where paths[i] is an array representing an absolute path to the ith folder in the file system.
For example, ["one", "two", "three"] represents the path "/one/two/three".
Two folders (not necessarily on the same level) are identical if they contain the same non-empty set of identical subfolders and underlying subfolder structure. The folders do not need to be at the root level to be identical. If two or more folders are identical, then mark the folders as well as all their subfolders.
Once all the identical folders and their subfolders have been marked, the file system will delete all of them. The file system only runs the deletion once, so any folders that become identical after the initial deletion are not deleted.
Return the 2D array ans containing the paths of the remaining folders after deleting all the marked folders. The paths may be returned in any order.
💡 Note:Folders /a and /c both contain subfolder "b", making them identical structures. Both /a and /c (and their subfolders) are deleted, leaving only /d and /d/a.
The key insight is to create unique signatures for each folder's subfolder structure using hash-based approach. Build a trie, generate signatures for folders with children, group folders with identical signatures, and mark duplicate groups for deletion. Best approach is hash-based signatures with Time: O(n × m + n log n), Space: O(n × m).
Common Approaches
✓
Brute Force Comparison
⏱️ Time: O(n² × m)
Space: O(n × m)
Build the folder tree structure, then for each folder, compare its complete subfolder structure with every other folder to find duplicates. Mark duplicate folders and their subfolders for deletion.
Hash-Based Folder Signatures
⏱️ Time: O(n × m + n log n)
Space: O(n × m)
Build a trie structure and create hash-based signatures for each folder's subfolder structure. Group folders with identical signatures and mark them for deletion in a single pass.
Brute Force Comparison — Algorithm Steps
Build trie from all folder paths
For each folder, compare its structure with all other folders
Mark duplicates and their subfolders for deletion
Collect remaining paths
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Build Trie
Create tree structure from folder paths
2
Compare All
Compare each folder's structure with all others
3
Mark Duplicates
Mark identical folder structures for deletion
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FOLDERS 1000
#define MAX_NAME_LEN 100
#define MAX_DEPTH 100
#define MAX_STRUCTURE_LEN 10000
typedef struct TrieNode {
struct TrieNode* children[MAX_FOLDERS];
char childNames[MAX_FOLDERS][MAX_NAME_LEN];
int childCount;
int isDeleted;
char paths[MAX_FOLDERS][MAX_DEPTH][MAX_NAME_LEN];
int pathLengths[MAX_FOLDERS];
int pathCount;
} TrieNode;
typedef struct {
TrieNode* node;
char path[MAX_DEPTH][MAX_NAME_LEN];
int pathLen;
} NodePath;
TrieNode* createNode() {
TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
node->childCount = 0;
node->isDeleted = 0;
node->pathCount = 0;
for (int i = 0; i < MAX_FOLDERS; i++) {
node->children[i] = NULL;
}
return node;
}
TrieNode* findChild(TrieNode* node, const char* name) {
for (int i = 0; i < node->childCount; i++) {
if (strcmp(node->childNames[i], name) == 0) {
return node->children[i];
}
}
return NULL;
}
TrieNode* addChild(TrieNode* node, const char* name) {
TrieNode* child = findChild(node, name);
if (child) return child;
child = createNode();
strcpy(node->childNames[node->childCount], name);
node->children[node->childCount] = child;
node->childCount++;
return child;
}
int cmpstr(const void* a, const void* b) {
return strcmp((const char*)a, (const char*)b);
}
void getStructure(TrieNode* node, char* result) {
if (node->childCount == 0) {
strcpy(result, "");
return;
}
char sortedNames[MAX_FOLDERS][MAX_NAME_LEN];
for (int i = 0; i < node->childCount; i++) {
strcpy(sortedNames[i], node->childNames[i]);
}
qsort(sortedNames, node->childCount, MAX_NAME_LEN, cmpstr);
strcpy(result, "");
for (int i = 0; i < node->childCount; i++) {
TrieNode* child = findChild(node, sortedNames[i]);
char childStruct[MAX_STRUCTURE_LEN];
getStructure(child, childStruct);
char item[MAX_STRUCTURE_LEN];
sprintf(item, "%s(%s)", sortedNames[i], childStruct);
if (i > 0) strcat(result, "|");
strcat(result, item);
}
}
void markDeleted(TrieNode* node) {
node->isDeleted = 1;
for (int i = 0; i < node->childCount; i++) {
markDeleted(node->children[i]);
}
}
void collectNodes(TrieNode* node, char path[][MAX_NAME_LEN], int pathLen, NodePath* allNodes, int* nodeCount) {
if (node->childCount > 0) {
allNodes[*nodeCount].node = node;
allNodes[*nodeCount].pathLen = pathLen;
for (int i = 0; i < pathLen; i++) {
strcpy(allNodes[*nodeCount].path[i], path[i]);
}
(*nodeCount)++;
}
for (int i = 0; i < node->childCount; i++) {
strcpy(path[pathLen], node->childNames[i]);
collectNodes(node->children[i], path, pathLen + 1, allNodes, nodeCount);
}
}
char* parseNextString(char* input, int* pos) {
while (input[*pos] && (input[*pos] == '[' || input[*pos] == ',' || input[*pos] == ' ')) (*pos)++;
if (input[*pos] == ']') return NULL;
if (input[*pos] != '"') return NULL;
(*pos)++;
static char result[MAX_NAME_LEN];
int len = 0;
while (input[*pos] && input[*pos] != '"') {
result[len++] = input[*pos];
(*pos)++;
}
result[len] = '\0';
if (input[*pos] == '"') (*pos)++;
return result;
}
int main() {
char line[100000];
fgets(line, sizeof(line), stdin);
char paths[MAX_FOLDERS][MAX_DEPTH][MAX_NAME_LEN];
int pathLengths[MAX_FOLDERS];
int pathCount = 0;
int pos = 0;
while (line[pos] && line[pos] != '[') pos++;
pos++;
while (line[pos] && line[pos] != ']') {
while (line[pos] && line[pos] != '[') pos++;
if (line[pos] != '[') break;
pos++;
pathLengths[pathCount] = 0;
char* str;
while ((str = parseNextString(line, &pos)) != NULL) {
strcpy(paths[pathCount][pathLengths[pathCount]], str);
pathLengths[pathCount]++;
}
while (line[pos] && line[pos] != ']') pos++;
if (line[pos] == ']') pos++;
pathCount++;
}
if (pathCount == 0) {
printf("[]\n");
return 0;
}
TrieNode* root = createNode();
for (int i = 0; i < pathCount; i++) {
TrieNode* current = root;
for (int j = 0; j < pathLengths[i]; j++) {
current = addChild(current, paths[i][j]);
}
}
NodePath allNodes[MAX_FOLDERS];
int nodeCount = 0;
char tempPath[MAX_DEPTH][MAX_NAME_LEN];
collectNodes(root, tempPath, 0, allNodes, &nodeCount);
for (int i = 0; i < nodeCount; i++) {
for (int j = i + 1; j < nodeCount; j++) {
TrieNode* node1 = allNodes[i].node;
TrieNode* node2 = allNodes[j].node;
if (!node1->isDeleted && !node2->isDeleted) {
char struct1[MAX_STRUCTURE_LEN], struct2[MAX_STRUCTURE_LEN];
getStructure(node1, struct1);
getStructure(node2, struct2);
if (strlen(struct1) > 0 && strcmp(struct1, struct2) == 0) {
markDeleted(node1);
markDeleted(node2);
}
}
}
}
printf("[");
int first = 1;
for (int i = 0; i < pathCount; i++) {
TrieNode* current = root;
int deleted = 0;
for (int j = 0; j < pathLengths[i]; j++) {
current = findChild(current, paths[i][j]);
if (current->isDeleted) {
deleted = 1;
break;
}
}
if (!deleted) {
if (!first) printf(",");
first = 0;
printf("[");
for (int j = 0; j < pathLengths[i]; j++) {
if (j > 0) printf(",");
printf("\"%s\"", paths[i][j]);
}
printf("]");
}
}
printf("]\n");
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(n² × m)
For each of n folders, compare with n other folders, each comparison takes O(m) time where m is average folder depth
n
2n
⚠ Quadratic Growth
Space Complexity
O(n × m)
Trie structure stores all paths, taking O(n × m) space where n is number of paths and m is average path length
n
2n
⚡ Linearithmic Space
18.5K Views
MediumFrequency
~35 minAvg. Time
425 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.