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]
Difficulty
and has an acceptance rate of about 67% (200k+ submissions).
Typical patterns to solve this problem:
- Array
- Hash Table
- String
AI Disclaimer
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.
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.
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.
Code Quality
Complexity Analysis
Other Solutions
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 |
Videos
Solved On The Same Day
- problem 1184: Distance Between Bus Stops
- problem 1342: Number of Steps to Reduce a Number to Zero
- problem 1399: Count Largest Group
- problem 1496: Path Crossing
- problem 1646: Get Maximum in Generated Array
- problem 1893: Check if All the Integers in a Range Are Covered
- problem 2404: Most Frequent Even Element
- problem 2432: The Employee That Worked on the Longest Task
- problem 2451: Odd String Difference
- problem 2540: Minimum Common Value
- problem 1169: Invalid Transactions
- problem 1711: Count Good Meals
- problem 1781: Sum of Beauty of All Substrings
- problem 1865: Finding Pairs With a Certain Sum
- problem 1871: Jump Game VII
- problem 2013: Detect Squares
Extra
- 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