Problem 609

Abstract / Summary

Find groups of files with the same content in a system using their directory paths and file contents.

Note

The full problem description, including helpful examples, can be found on LeetCode.

Python 0609.py

class Solution:
    def findDuplicate(self, paths: List[str]) -> List[List[str]]:
        content = defaultdict(list)
        for p in paths:
            directory = p.split(" ")
            path = directory.pop(0)          # first item is the path
            for file in directory:           # followed by files
                name, text = file.split("(") # keep final ")", it doesn't matter
                content[text].append(path + "/" + name)

        for c in content:
            if len(content[c]) > 1:
                yield content[c]
13 lines | 560 bytes | submitted December 12, 2023 | GitHub   25% comment ratio | tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 67% (200k+ submissions).

Typical patterns to solve this problem:
  • Array
  • Hash Table
  • String
I solved 663 easy, 1250 medium and 309 hard problems

AI Disclaimer

Every single line of code was written by me, 100% from scratch, between August 2023 and August 2024.
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.

See this dedicated page for more details.
LeetCode profile | GitHub repo

Code Walkthrough

Overview

The provided implementation processes a collection of directory descriptions to locate groups of files that share identical content. Each input string encodes a directory path followed by one or more file specifications, where a file is expressed as name(content). The algorithm builds a mapping from file content to the full paths of files that contain that content and then yields only those groups that contain more than one file, indicating duplicates.

Key Steps

Parsing the Directory Line

For every entry in the input list the code separates the directory component from the file specifications. The split on a single space yields a list whose first element is the directory path and whose remaining elements describe individual files.

for p in paths:
    directory = p.split(" ")
    path = directory.pop(0)          # first item is the path

Extracting File Name and Content

Each file token is further divided at the opening parenthesis. The part before the parenthesis becomes the file name, while the remainder-including the closing parenthesis-represents the file’s content. This approach preserves the exact content string as it appears in the input.

    for file in directory:           # followed by files
        name, text = file.split("(") # keep final ")", it doesn't matter

Grouping Files by Their Content

A defaultdict of lists stores the association between a content string and the full path of each file that contains it. By appending path + "/" + name the code constructs the absolute file path for later reporting.

        content[text].append(path + "/" + name)

Emitting Duplicate Groups

After all lines have been processed, the algorithm iterates over the content-to-paths mapping. Whenever a content key maps to more than one path, the corresponding list is yielded as a group of duplicates. Using yield makes the function a generator, allowing callers to consume results lazily.

for c in content:
    if len(content[c]) > 1:
        yield content[c]

Edge Cases Handled

The routine correctly aggregates files that appear in different directories but share the same content, because the content string is the sole key in the grouping structure. It also tolerates any number of files listed after a directory path; the inner loop processes each token independently. By retaining the closing parenthesis in the text variable, the implementation accommodates content strings that might contain parentheses themselves, as the split occurs only at the first opening parenthesis. Empty directories (lines that contain only a path and no file tokens) result in an empty directory list after the pop, and the inner loop simply does not execute, leaving the overall result unaffected.

Performance Optimizations

The use of defaultdict(list) eliminates the need for explicit existence checks before appending, reducing conditional overhead during the grouping phase. Constructing the full file path with a single string concatenation (path + "/" + name) avoids repeated string formatting calls. By yielding duplicate groups instead of building a final list, the function streams results, which can be advantageous when the caller processes groups incrementally or when the total number of duplicate groups is large. The algorithm processes each file token exactly once, ensuring that work is proportional to the size of the input without unnecessary recomputation.

written by openai gpt

ELI5 - Simplified Explanation

Imagine a giant toy box filled with folders that hold different notes written on pieces of paper. This code is like a clever robot assistant that looks through all the folders to find notes that say exactly the same thing.

First, the robot starts with an empty notebook to keep track of what it finds. It looks at the big list of folders one by one. It picks up a folder, sees where it is, and then opens it to find all the little paper notes inside. Each note has a filename and a special message written on it.

The robot writes down the message in its notebook and puts the name of the folder and the filename right next to it. It does this for every single note in every single folder.

Once the robot has checked every paper, it looks at its notebook to see which messages appear more than once. If it finds a message that shows up in two or even three different places, it puts a sticky note on those files so you know that they are twins. It ignores any notes that are unique because those are already special on their own.

written by google gemini

Code Quality

Several LLMs ranked my code quality on a scale from 1 (very poor) to 10 (outstanding):
n = 26 | median = 7 | μ = 6.46 | σ = 1.78

Complexity Analysis

not analyzed yet

Other Solutions

I wrote a basic crawler to find other solutions to that problem.
Obviously, I did that after I solved the problem myself.

In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.

And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.

(click on a column header to sort the table)
author
author solutions
www AlgoMonster Java C++ Python TS
WalkCCC Java C++ Python
leetcode.ca Java C++ Python Go TS
LeetcodeHelp Java C++ Python
Progiez Java C++ Python
github BigEggStudy C#
black-shadows C++
charles-wangkai Java
everthis JS
fartem Ruby
halfrost Go
JoshCrozier JS
linouk23 C++
lkwq007 Python
ruoru Rust
suxrobGM C#
varunu28 Java
vthwang Java
YuriSpiridonov Python
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, Python, TypeScript
LeetcodeHelp C++, Java, Python
Progiez C++, Java, Python
BigEggStudy C#
black-shadows C++, C++
charles-wangkai Java
everthis JavaScript
fartem Ruby
halfrost Go
JoshCrozier JavaScript
linouk23 C++
lkwq007 Python
ruoru Rust
suxrobGM C#
varunu28 Java
vthwang Java
YuriSpiridonov Python
32 links | 19 authors | 9 languages

Videos

14 videos   did my crawler come up with invalid videos ? drop me a line.

Solved On The Same Day

17 solutions   December 12, 2023

Extra

There are a few extra pages giving you some insights into my setup:
  • Tech Stack - my development environment and tools
  • AI - how AI helped me create this website (NOT solving the problems)
  • Progress - progression over time
  • Quality - code quality