单词子集

标签: 数组 哈希表 字符串

难度: Medium

给你两个字符串数组 words1 和 words2

现在,如果 b 中的每个字母都出现在 a 中,包括重复出现的字母,那么称字符串 b 是字符串 a子集

  • 例如,"wrr""warrior" 的子集,但不是 "world" 的子集。

如果对 words2 中的每一个单词 bb 都是 a 的子集,那么我们称 words1 中的单词 a 通用单词

以数组形式返回 words1 中所有的通用单词。你可以按 任意顺序 返回答案。

示例 1:

输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","o"]
输出:["facebook","google","leetcode"]

示例 2:

输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["l","e"]
输出:["apple","google","leetcode"]

示例 3:

输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","oo"]
输出:["facebook","google"]

示例 4:

输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["lo","eo"]
输出:["google","leetcode"]

示例 5:

输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["ec","oc","ceo"]
输出:["facebook","leetcode"]

提示:

  • 1 <= words1.length, words2.length <= 104
  • 1 <= words1[i].length, words2[i].length <= 10
  • words1[i]words2[i] 仅由小写英文字母组成
  • words1 中的所有字符串 互不相同

Submission

运行时间: 120 ms

内存: 19.4 MB

class Solution:
    def wordSubsets(self, words1, words2):
        words2 = list(set(words2))
        def jlzd(words):
            # 建立字典
            d = {}
            for word in words:
                for i in word:
                    if i not in d:
                        d[i] = word.count(i)
                    else:
                        if d[i] < word.count(i):
                            d[i] = word.count(i)
            return d
        d = jlzd(words2)
        ls = []
        for i in words1:
            bool = True
            for j in d.keys():
                if i.count(j) < d[j]:
                    bool = False
                    break
            if bool:
                ls.append(i)

        return ls

Explain

首先,将 words2 中的单词集合化,以去除重复的单词。接着,创建一个函数 jlzd 来计算 words2 中所有单词的最大字母频率需求。这个字典 d 将存储每个字符的最大出现次数,这是通过遍历 words2 的每个单词并更新每个字符的出现次数来实现的。然后,遍历 words1 中的每个单词,检查它是否包含字典 d 中所有字母的最小需求次数。如果某个单词满足所有条件,则认为它是通用单词,并将其添加到结果列表中。

时间复杂度: O(B*L + A*M)

空间复杂度: O(C + A)

class Solution:
    def wordSubsets(self, words1, words2):
        words2 = list(set(words2))  # 去除words2中的重复单词
        def jlzd(words):
            # 建立字典存储每个字符的最大出现次数
            d = {}
            for word in words:
                for i in word:
                    if i not in d:
                        d[i] = word.count(i)
                    else:
                        if d[i] < word.count(i):
                            d[i] = word.count(i)
            return d
        d = jlzd(words2)  # 计算words2中所有单词的最大字母频率需求
        ls = []  # 初始化结果列表
        for i in words1:
            bool = True
            for j in d.keys():
                if i.count(j) < d[j]:
                    bool = False
                    break
            if bool:
                ls.append(i)  # 如果i满足所有条件,则添加到结果列表中

        return ls

Explore

在处理`words2`时选择去除重复单词是为了简化问题和提高效率。重复的单词在计算最大字母频率需求时,不会改变结果,因为重复的单词提供的字母频率信息是相同的。这样,去除重复项后,可以减少后续操作的计算量,只需要分析更少的单词来确定每个字符的最大需求频率。

这种选择可能是为了减少代码复杂度或者是考虑到实现的简便性。但是,这种方法效率较低,因为它会多次计算同一单词中字符的频率。更高效的方法是首先为每个单词建立一个字符频率字典,然后再比较更新全局的最大频率字典。这样可以减少重复的计数操作,提高算法的效率。

题解中没有明确指出如何处理`words1`和`words2`为空的情况。通常,如果`words2`为空,则没有特定的字母频率需求,因此`words1`中的所有单词都应被认为是通用的;如果`words1`为空,则结果自然为空列表。在实现时,应该在函数开始时检查这些条件,适当地返回空列表或`words1`的全部内容。

使用`break`跳出循环的策略可以提高算法效率,因为它避免了在确定一个单词不符合条件后进行不必要的比较。这种策略可以尽早终止对当前单词的检查,节省时间。进一步优化可能包括使用更高效的数据结构来存储和比较频率,例如使用数组代替字典来存储字母频率,尤其是在字符集较小的情况下,如仅包含英文字母的场景。