Problem 1002

Abstract / Summary

Find the characters that appear in every string and list each character as many times as it appears in all strings.

Note

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

Python 1002.py

class Solution:
    def commonChars(self, words: List[str]) -> List[str]:
        all = None
        for w in words:
            freq = defaultdict(int)
            for c in w:
                freq[c] += 1

            if all:
                for f in all:
                    all[f] = min(all[f], freq[f])
            else:
                all = freq

        for a in all:
            for _ in range(all[a]):
                yield a
17 lines | 452 bytes | submitted December 2, 2023 | GitHub   tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 75% (400k+ 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 computes the characters that appear in all strings of the input list words. It returns each common character as many times as it occurs in the smallest frequency across the words. The algorithm proceeds by building a frequency map for each word, intersecting these maps, and finally yielding the resulting characters.

Key Steps

Initialization

all = None

A variable named all is created to hold the cumulative intersection of character frequencies. It starts as None to indicate that no frequency map has been processed yet.

Frequency Counting for a Single Word

freq = defaultdict(int)
for c in w:
    freq[c] += 1

For each word w in the input, a defaultdict of integers records how many times each character appears. This step isolates the per-word character distribution before it is merged with the global intersection.

Intersection Update

if all:
    for f in all:
        all[f] = min(all[f], freq[f])
else:
    all = freq

When processing the first word, all is simply assigned the freshly built freq. For subsequent words, the algorithm iterates over the keys already present in all and reduces each count to the minimum of the existing value and the count in the current word’s freq. Characters absent from the current word automatically receive a count of zero because freq[f] defaults to 0, effectively removing them from the intersection.

Result Generation

for a in all:
    for _ in range(all[a]):
        yield a

After all words have been examined, the final frequency map all contains the exact number of times each character should appear in the output. The nested loops emit each character a repeatedly according to its stored count, using a generator (yield) to produce the result lazily.

Edge Cases Handled

The algorithm gracefully manages words that contain no overlapping characters. Because the intersection step uses min with a default of 0 for missing keys, any character that disappears in a later word will have its count reduced to 0. Consequently, the final generation loop will produce no output for that character, yielding an empty result when no common characters exist.

When the input list consists of a single word, the else branch assigns all directly to that word’s frequency map. The subsequent generation step then yields each character exactly as many times as it appears in the sole word, satisfying the definition of “common to all words” in the trivial single-element case.

If a word contains repeated characters, the frequency counting step records the exact multiplicity, and the intersection step preserves the smallest multiplicity across all words. This ensures that characters are emitted the correct number of times, even when some words have higher counts than others.

Performance Optimizations

The implementation avoids constructing intermediate full lists of characters. By using a defaultdict for frequency counting, it achieves constant-time updates for each character occurrence. The intersection step iterates only over keys already present in the cumulative map, which limits work to characters that have survived previous intersections, reducing unnecessary comparisons.

The final output is produced via a generator (yield). This lazy approach means that the caller can consume the result incrementally without allocating a complete list in memory, which is advantageous when the result set is large. The combination of in-place frequency updates and lazy emission minimizes both time spent on redundant data structures and memory footprint.

written by openai gpt

ELI5 - Simplified Explanation

Imagine a group of friends, each carrying a bag filled with letter blocks. The goal is to see which letters appear in every single friend’s bag, and to keep only as many of each letter as everyone has in common.

The code starts by looking at the first friend’s bag and keeping track of how many of each letter they have. Then, it looks at the next friend’s bag. If a friend has five blocks of a certain letter but someone else only has two, the code decides to keep just those two, because that is the smallest amount everyone can share. It repeats this process for every bag in the group, shrinking the collection down until only the shared letters remain.

After checking every bag, the code looks at the final list of shared letters and counts them up. For every letter it saved, it pulls that many blocks out of the imaginary pile to show what was found.

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 = 5 | μ = 5.19 | σ = 1.90

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 C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java Go TS
LeetcodeHelp C++ Python Java
Progiez C++ Python Java
github BigEggStudy C#
black-shadows C++
chandansgowda Python
charles-wangkai Java
DimitrisJim C
everthis JS
fartem Ruby
fsq C++
Garvit244 Python
halfrost Go
JoshCrozier JS
keineahnung2345 C++
Krazune C++
lkwq007 Python
lzl124631x C++
shreymehul C#
suxrobGM C#
varunu28 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++
chandansgowda Python
charles-wangkai Java
DimitrisJim C
everthis JavaScript
fartem Ruby
fsq C++
Garvit244 Python
halfrost Go
JoshCrozier JavaScript
keineahnung2345 C++
Krazune C++
lkwq007 Python
lzl124631x C++
shreymehul C#
suxrobGM C#
varunu28 Java
YuriSpiridonov Python
37 links | 24 authors | 9 languages

Videos

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

Similar Problems

1 similar problem

Solved On The Same Day

1 easy
2 solutions   December 2, 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