Problem 1941

Abstract / Summary

Check if every character in a string appears the same number of times.

Note

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

Python 1941.py

class Solution:
    def areOccurrencesEqual(self, s: str) -> bool:
        freq = defaultdict(int)
        for c in s:
            freq[c] += 1

        return min(freq.values()) == max(freq.values())
7 lines | 208 bytes | submitted January 26, 2024 | GitHub   tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

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

Typical patterns to solve this problem:
  • Counting
  • 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 defines a Solution class with a single method areOccurrencesEqual. The method determines whether every distinct character in the input string s appears the same number of times. It returns True when all character frequencies are identical and False otherwise.

Key Steps

The algorithm proceeds through three distinct phases, each illustrated with a focused code excerpt.

Frequency Container Initialization

freq = defaultdict(int)

A defaultdict from the collections module is created with int as the default factory. This choice eliminates the need for explicit existence checks before incrementing a character’s count, allowing the code to treat missing keys as having a count of zero automatically.

Single-Pass Counting Loop

for c in s:
    freq[c] += 1

The method iterates over every character c in the input string. For each character, the corresponding entry in freq is incremented. Because the container is a defaultdict, the first encounter of any character creates a new entry with an initial value of 0, which is then increased to 1. This loop runs exactly once over the input, guaranteeing linear processing relative to the length of s.

Equality Check of Extremal Frequencies

return min(freq.values()) == max(freq.values())

After the counting phase, the method extracts the collection of frequency values. It computes the smallest and largest values among them and compares them for equality. If the minimum and maximum are the same, every character count must be identical, and the method returns True; otherwise it returns False.

Edge Cases Handled

The implementation naturally accommodates strings that consist of a single repeated character. In such a case, the frequency dictionary contains a single entry, and both min and max return the same count, leading to a True result.

It also correctly processes strings containing a mixture of uppercase and lowercase letters, digits, punctuation, or any other Unicode code point, because the dictionary keys are the characters themselves without any transformation. The counting loop treats each distinct code point independently, ensuring that case sensitivity and symbol variety are respected.

When the input string contains multiple distinct characters that each appear the same number of times-such as "aabbcc" or "112233"-the frequency values are uniform, and the final comparison yields True. Conversely, any deviation in occurrence count, for example "aabbbc" where 'a' appears twice, 'b' three times, and 'c' once, results in differing min and max values, and the method returns False.

The use of defaultdict also sidesteps the need for explicit initialization of each character’s counter, which would otherwise require a conditional check for key existence. This design choice simplifies handling of characters that appear only once.

Performance Optimizations

The code exhibits several performance-focused decisions.

First, the counting phase executes in a single linear pass over the input string, avoiding any nested loops or repeated scans.

Second, employing defaultdict(int) removes the overhead of conditional key existence checks (if key in dict) that would be required with a plain dictionary. This results in fewer Python bytecode instructions per iteration.

Third, the final equality test leverages built-in min and max functions applied to the view returned by freq.values(). These functions are implemented in C and iterate over the values efficiently, providing a fast way to obtain the extremal frequencies without manual traversal.

Overall, the combination of a single pass, constant-time updates, and native C-level aggregation functions yields a solution that scales well with the size of the input string while maintaining concise and readable code.

written by openai gpt

ELI5 - Simplified Explanation

Imagine you have a big bucket full of different colored building blocks. You want to see if every color appears the exact same number of times.

First, you pick up each block one by one and put it into a special bag that remembers how many of each color you have found. You walk through the whole pile from the beginning to the end, counting every single block you see.

Once all the blocks are counted, you look at your tally for each color. You find the smallest number of blocks for any color and the largest number of blocks for any color. If those two numbers are the same, it means every color you have appears the same amount of times. If they are different, it means some colors have more blocks than others.

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 = 8 | μ = 7.22 | σ = 1.57

Complexity Analysis

Time: linear
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 C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java Go PHP TS
Progiez C++ Python Java
github black-shadows C++
chandansgowda Python
charles-wangkai Java
DimitrisJim C
everthis JS
fartem Ruby
fsq C++
JoshCrozier JS
lkwq007 Python
muhammadfarhankt Go
suxrobGM C#
varunu28 Java
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, PHP, Python, TypeScript
Progiez C++, Java, Python
black-shadows C++, C++
chandansgowda Python
charles-wangkai Java
DimitrisJim C
everthis JavaScript
fartem Ruby
fsq C++
JoshCrozier JavaScript
lkwq007 Python
muhammadfarhankt Go
suxrobGM C#
varunu28 Java
28 links | 16 authors | 10 languages

Videos

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

Similar Problems

2 similar problems

Solved On The Same Day

5 solutions   January 26, 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