重新分配字符使所有字符串都相等

标签: 哈希表 字符串 计数

难度: Easy

给你一个字符串数组 words(下标 从 0 开始 计数)。

在一步操作中,需先选出两个 不同 下标 ij,其中 words[i] 是一个非空字符串,接着将 words[i] 中的 任一 字符移动到 words[j] 中的 任一 位置上。

如果执行任意步操作可以使 words 中的每个字符串都相等,返回 true ;否则,返回 false

 

示例 1:

输入:words = ["abc","aabc","bc"]
输出:true
解释:words[1] 中的第一个 'a' 移动到 words[2] 的最前面。
使 words[1] = "abc" 且 words[2] = "abc" 。
所有字符串都等于 "abc" ,所以返回 true

示例 2:

输入:words = ["ab","a"]
输出:false
解释:执行操作无法使所有字符串都相等。

 

提示:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 100
  • words[i] 由小写英文字母组成

Submission

运行时间: 35 ms

内存: 16.1 MB

class Solution:
    def makeEqual(self, words: List[str]) -> bool:
        n = len(words)
        s = "".join(words)
        char_map = Counter(s)
        for v in char_map.values():
            if v % n != 0:
                return False

        return True


Explain

题解的核心思路是首先将所有字符串合并成一个单一的字符串,并使用计数器统计每个字符的总出现次数。然后,检查每个字符的出现次数是否能够被字符串数组的长度整除。如果每个字符的出现次数都可以均匀分配到每个字符串中,则所有字符串都可以通过重新分配字符变得相同。否则,就不可能使所有字符串相等。

时间复杂度: O(N)

空间复杂度: O(1)

class Solution:
    def makeEqual(self, words: List[str]) -> bool:
        n = len(words)  # 字符串数组的长度
        s = ''.join(words)  # 将所有字符串合并成一个大字符串
        char_map = Counter(s)  # 对合并后的字符串中的字符进行计数
        for v in char_map.values():  # 遍历每个字符的出现次数
            if v % n != 0:  # 如果字符的出现次数不能被字符串数组的长度整除
                return False  # 不能均匀分配,返回False
        return True  # 所有字符都可以均匀分配,返回True

Explore

这种方法实际上并没有直接考虑字符在各个字符串中的初始分布。它主要关注的是字符在所有字符串中的总数量是否可以平均分配到每个字符串上。初始分布是不影响最终结果的,因为题目的目的是通过重新分配字符来使所有字符串相等,而不是保持每个字符串的字符分布不变。

可以直接判断字符出现次数是否能被字符串数组的长度整除,因为这是检查能否将每个字符均匀分配到每个字符串中的必要且充分条件。如果每个字符的总数能被字符串的数量整除,那么就可以确保这些字符可以均匀分配到每个字符串中,每个字符串得到相同数量的每种字符。不存在字符总数能整除但无法合理重分配的情况,因为唯一的要求是每种字符的数量在每个字符串中要一致。

使用Counter计数器来统计字符数通常是高效的,因为它的时间复杂度与合并后字符串的长度线性相关。然而,在处理非常大的字符串数组时,性能瓶颈可能出现在内存消耗上,尤其是当合并后的字符串非常长时。此外,如果字符种类非常多,Counter也会消耗更多的内存。尽管如此,对于大多数实际应用场景,Counter的性能是可以接受的。

算法本身不需要针对字符种类进行调整,因为它是基于字符出现的总次数来进行判断的,而并非依赖于字符是哪种具体的类型。无论是小写字母、大写字母还是符号,只要统计各个字符的出现总次数,并检查这些次数是否可以被字符串数组的长度整除即可。因此,算法适用于任何字符类型。