Redistribute Characters to Make All Strings Equal: Frequency Divisibility Check
LeetCode 1897. Redistribute Characters to Make All Strings Equal sounds like it might involve complicated string manipulation. It does not. The key insight is that you can move any character from any string to any other string, as many times as you want. That freedom simplifies the problem enormously. You just need to check whether every character's total count divides evenly by the number of strings.
The problem
Given an array of strings words, you can pick any character from any string and move it to any position in any other string. Return true if you can make all strings equal using any number of moves.
Example: words = ["abc", "bca", "cab"]
There are 3 strings. Pooling all characters: a appears 3 times, b appears 3 times, c appears 3 times. Since 3 % 3 == 0 for every character, the answer is true. Each string can end up with one 'a', one 'b', and one 'c'.
The key insight
Because you can move characters freely between strings with no restrictions, the original arrangement does not matter at all. The only thing that matters is the total count of each character across all strings combined. If you have n strings and a character appears count times total, you need count to be divisible by n so that each string gets exactly count / n copies. If even one character fails this check, the answer is false.
Visual walkthrough
Step 1: Pool all characters from ["abc", "aaa", "bc"] where n = 3
Combine every character from every string into one pool: a, b, c, a, a, a, b, c.
Step 2: Count every character
a appears 4 times, b appears 2 times, c appears 2 times.
Step 3: Check divisibility by n = 3
a has count 4, and 4 % 3 = 1, which is not zero. We cannot split 4 copies of 'a' evenly into 3 strings.
Step 4: A passing example with ["ab", "a", "b"]
a appears 2 times, b appears 2 times. Both 2 % 2 == 0. Return true.
The code
from collections import Counter
def make_equal(words: list[str]) -> bool:
n = len(words)
counts = Counter("".join(words))
return all(c % n == 0 for c in counts.values())
Let's walk through what each line does:
n = len(words)stores the number of strings. This is the divisor we need to check against.counts = Counter("".join(words))concatenates all strings into one big string, then counts the frequency of every character. This gives us the pooled character counts.return all(c % n == 0 for c in counts.values())checks whether every character count is divisible byn. If any count has a nonzero remainder, we cannot distribute that character evenly, so we returnFalse.
Complexity analysis
| Complexity | Why | |
|---|---|---|
| Time | O(n * k) | where n is the number of strings and k is the average string length, since we visit every character once |
| Space | O(26) = O(1) | the counter holds at most 26 lowercase English letters |
The building blocks
This problem breaks down into two reusable pieces.
1. Frequency counting
Count how many times each element appears in a collection. This is the same brick used in Group Anagrams, First Unique Character in a String, and dozens of other hash map problems. The template is always the same:
from collections import Counter
counts = Counter(items)
2. Divisibility check
After counting, you verify a mathematical property on every count. Here the property is count % n == 0. This "check all values satisfy a condition" pattern shows up whenever you need to confirm that a distribution is possible. Python's all() with a generator expression is the clean way to write it.
Edge cases
- Single string. If
n == 1, every count is trivially divisible by 1. Returntrueimmediately. - All strings already equal. The counts will all be divisible by
n. The algorithm handles this without special logic. - Empty strings in the array. Empty strings contribute zero characters. They still count toward
n, making it harder for counts to divide evenly. The algorithm handles this correctly. - All characters are the same. For example
["aaa", "aa", "a"]. The total count is 6,nis 3, and6 % 3 == 0. Returntrue.
From understanding to recall
This problem feels almost too simple once you see the solution. "Just count characters and check divisibility." But the real skill is recognizing that free redistribution means you only need to care about totals, not positions. That leap from "I can move characters anywhere" to "I only need to check divisibility" is the insight worth drilling.
Spaced repetition helps you internalize that connection. CodeBricks breaks the problem into its two building blocks and presents them at increasing intervals. After a few review cycles, the moment you see "you can freely rearrange," your brain jumps straight to frequency counting and divisibility. No searching for the approach. You already have it.
Related posts
- Group Anagrams - Another frequency counting problem
- Data Structure: Hash Maps - The foundation for character counting
- First Unique Character in a String - Frequency counting at its simplest