Problem 1897
Question statement
You are given an array of strings words (0-indexed). In one operation, pick two distinct indices $\texttt{i}$ and $\texttt{j}$, where $\texttt{words[i]}$ is a non-empty string, and move any character from $\texttt{words[i]}$ to any position in $\texttt{words[j]}$. Return $\texttt{true}$ if you can make every string in words equal using any number of operations, and $\texttt{false}$ otherwise.
Solution
Main idea:
This is simply a redistribution problem in disguise. A valid rearrangement is possible only if every distinct letter (across all words) appears with a frequency divisible by the length of words. Otherwise, there will exist a letter (counted with multiplicity) that will appear in some but not all words.
- Join all words into one big string $\texttt{s}$ and hash all distinct elements using a $\texttt{set()}$
- For $\texttt{i}$ in this set, count the number of occurrences of this $\texttt{i}$ in $\texttt{s}$.
- If there is a count that is not divisible by $\texttt{len(words)}$, then return $\texttt{False}$
- Otherwise return $\texttt{True}$.
Code
1 | def makeEqual(self, words: List[str]) -> bool: |
Alternate idea:
You can trade off the built in count function iterating through the non-hashable string, with constructing a dictionary that counts the number of occurrences of each letter across words, and then going across the dictionary to see if each count is divisible by $\texttt{len(words)}$.
Alternate code:
1 | def makeEqual2(self, words: List[str]) -> bool: |
Comments:
In both cases, the time complexity is O($\texttt{len(s)}$).
At the time of submission, the first approach passes leetcode submission cases in 69ms, beating 45.25% of users. It uses 17.38MB of memory, beating 7.46% of users. The second approach passes leetcode submission cases in 75ms, beating 30.2% of users. It uses 17.55MB of memory, beating 6.55% of users.
Looking through other solutions, a few take-aways:
- Python has a built in $\texttt{Counter()}$ (optimized) function that basically builds the desired dictionary for us. The relevant code seems to be
1 | dic: dict[str, int] = Counter(''.join(words)) |
- Another pretty cool idea that people seem to use is to join the words together into a string, create an array of length 26, and increment the value at the $\texttt{i}^{th}$ spot whenever the corresponding letter is encountered while scanning through this string. Finally check if each entry in this array is divisible by $\texttt{len(words)}.$