Problem
You are given two string arrays words1
and words2
.
A string b
is a subset of string a
if every letter in b
occurs in a
including multiplicity.
For example, "wrr"
is a subset of "warrior"
but is not a subset of "world"
.
A string a
from words1
is universal if for every string b
in words2
, b
is a subset of a
.
Return an array of all the universal strings in words1
. You may return the answer in any order .
https://leetcode.com/problems/word-subsets/
Example 1:
Input: words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","o"]
Output: ["facebook","google","leetcode"]
Example 2:
Input: words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["l","e"]
Output: ["apple","google","leetcode"]
Constraints:
1 <= words1.length, words2.length <= 10⁴
1 <= words1[i].length, words2[i].length <= 10
words1[i]
and words2[i]
consist only of lowercase English letters.
All the strings of words1
are unique .
Test Cases
1 2 class Solution : def wordSubsets (self, words1: List [str ], words2: List [str ] ) -> List [str ]:
solution_test.py 1 2 3 4 5 6 7 8 9 10 11 12 13 import pytestfrom solution import Solutionfrom solution2 import Solution as Solution2@pytest.mark.parametrize('words1, words2, expected' , [ (["amazon" ,"apple" ,"facebook" ,"google" ,"leetcode" ], ["e" ,"o" ], ["facebook" ,"google" ,"leetcode" ] ), (["amazon" ,"apple" ,"facebook" ,"google" ,"leetcode" ], ["l" ,"e" ], ["apple" ,"google" ,"leetcode" ] ), ] )@pytest.mark.parametrize('sol' , [Solution( ), Solution2( )] ) def test_solution (sol, words1, words2, expected ): assert sorted (sol.wordSubsets(words1, words2)) == sorted (expected)
Thoughts
因为 universal word 能够包含 words2 中的所有单词,可以先汇总 words2 所有单词的信息。
对于 words2 中的每个单词,统计其中每个字符的出现次数。然后把每个单词的字符次数合并,对于任何一个字符,取最大的出现次数(相当于 Python collections.Counter 的 union
操作(operator |
)。
然后遍历 words1 的每一个单词,看是否包含汇总之后的所有字符的次数。
时间复杂度 O(m + n)
,额外的空间复杂度 O(1)
。
Code
solution.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from collections import defaultdictclass Solution : def wordSubsets (self, words1: list [str ], words2: list [str ] ) -> list [str ]: max2 = lambda a, b: a if a >= b else b occurs: dict [str , int ] = defaultdict(int ) for word in words2: counter: dict [str , int ] = defaultdict(int ) for c in word: counter[c] += 1 for c, cnt in counter.items(): occurs[c] = max2(occurs[c], cnt) result: list [str ] = [] for word in words1: counter: dict [str , int ] = defaultdict(int ) for c in word: counter[c] += 1 for c, cnt in occurs.items(): if counter[c] < cnt: break else : result.append(word) return result
用 collections.Counter 会慢一些:
solution2.py 1 2 3 4 5 6 7 8 9 10 11 from typing import Counterclass Solution : def wordSubsets (self, words1: list [str ], words2: list [str ] ) -> list [str ]: occurs: dict [str , int ] = Counter() for word in words2: counter = Counter(word) occurs |= counter return [word for word in words1 if Counter(word) >= occurs]