Problem 2273

Abstract / Summary

Given a list of strings, remove groups that are anagrams of each other and keep only one string from each group.

Note

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

Python 2273.py

class Solution:
    def removeAnagrams(self, words: List[str]) -> List[str]:
        last = ""
        for w in words:
            fingerprint = sorted(w)
            if last != fingerprint:
                last = fingerprint
                yield w
8 lines | 258 bytes | submitted February 2, 2024 | GitHub   tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 70% (300k+ submissions).

Typical patterns to solve this problem:
  • Array
  • Hash Table
  • Sorting
  • 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 defines a class with a method that iterates through a sequence of words and emits only those that are not anagrams of the immediately preceding word. The method uses a generator pattern, producing results on demand rather than constructing an intermediate collection.

Key Steps

The algorithm begins by establishing a placeholder for the fingerprint of the previous word:

last = ""

During each iteration over the input list, the current word is transformed into a canonical representation by sorting its characters:

fingerprint = sorted(w)

The sorted list of characters serves as a fingerprint that is identical for any two words that are anagrams of each other. The next step compares this fingerprint with the stored fingerprint of the previous word:

if last != fingerprint:

When the fingerprints differ, the algorithm updates the stored fingerprint and yields the current word:

last = fingerprint
yield w

These statements together ensure that only the first word in any consecutive run of anagrams is emitted.

Edge Cases Handled

The logic gracefully handles an empty input sequence by never entering the loop, resulting in no output. For a single-element list, the initial comparison succeeds because the placeholder last does not match the fingerprint of the sole word, causing that word to be yielded. When two or more consecutive words share the same set of characters, the fingerprint comparison fails after the first occurrence, and the subsequent anagrams are omitted. Identical words are also treated as anagrams because sorting yields identical fingerprints, so duplicates that appear consecutively are suppressed. Non-consecutive anagrams are not removed; the fingerprint is reset after a different word appears, allowing the later anagram to be emitted.

Performance Characteristics

The use of a generator (yield) means that the method produces each qualifying word as soon as it is identified, avoiding the allocation of a full result list in memory. This lazy evaluation is especially beneficial when the input list is large or when the consumer of the generator stops early. Storing only the most recent fingerprint (last) keeps the memory footprint minimal, as the algorithm does not retain fingerprints for all processed words. The sorting operation creates a temporary list of characters for each word, providing a straightforward way to detect anagrams without additional data structures. By reusing the computed fingerprint for the comparison and the subsequent update of last, the implementation avoids redundant work within a single iteration.

written by openai gpt

ELI5 - Simplified Explanation

Imagine a row of blocks, where each block has a different word written on it. This set of instructions is like a helper holding two boxes while walking down the line of blocks.

The helper looks at the word on the block. The helper then rearranges the letters of that word alphabetically to make a special secret code for that word. Think of this as sorting the letters like putting crayons in order by color.

The helper keeps one box to remember the secret code of the last block looked at. If the secret code of the current block is different from the code in the box, the helper knows it is a new kind of word. The helper then shouts out the word for everyone to hear, and puts the new secret code inside the box to replace the old one. If the secret code matches what is already in the box, the helper ignores the word and just keeps moving along the line to the next block.

written by google gemini

Code Quality

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

Complexity Analysis

Time: polynomial
As a rule of thumb, the maximum input size for one second execution time is
  • factorial: up to 10 elements
  • exponential: up to 20 elements
  • polynomial: a few thousand elements
  • loglinear: up to 100,000 elements
  • linear: a few million elements
  • logarithmic: a billion elements
  • constant: practically unlimited
generated automatically

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 JS Java C++ Python Go Rust TS
Progiez Java C++ Python
github charles-wangkai Java
everthis JS
fsq C++
JoshCrozier JS
lkwq007 Python
muhammadfarhankt Go
varunu28 Java
withaarzoo C++
yuanliu666 Kotlin
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, JavaScript, Python, Rust, TypeScript
Progiez C++, Java, Python
charles-wangkai Java
everthis JavaScript
fsq C++
JoshCrozier JavaScript
lkwq007 Python
muhammadfarhankt Go
varunu28 Java
withaarzoo C++
yuanliu666 Kotlin
26 links | 13 authors | 8 languages

Videos

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

Similar Problems

1 similar problem

Solved On The Same Day

5 solutions   February 2, 2024

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