题目描述
我们给出两个单词数组 A
和 B
。每个单词都是一串小写字母。
现在,如果 b
中的每个字母都出现在 a
中,包括重复出现的字母,那么称单词 b
是单词 a
的子集。 例如,“wrr”
是 “warrior”
的子集,但不是 “world”
的子集。
如果对 B
中的每一个单词 b
,b
都是 a
的子集,那么我们称 A
中的单词 a
是_通用的_。
你可以按任意顺序以列表形式返回 A
中所有的通用单词。
样例
输入:A = ["amazon","apple","facebook","google","leetcode"], B = ["e","o"]
输出:["facebook","google","leetcode"]
输入:A = ["amazon","apple","facebook","google","leetcode"], B = ["l","e"]
输出:["apple","google","leetcode"]
输入:A = ["amazon","apple","facebook","google","leetcode"], B = ["e","oo"]
输出:["facebook","google"]
输入:A = ["amazon","apple","facebook","google","leetcode"], B = ["lo","eo"]
输出:["google","leetcode"]
输入:A = ["amazon","apple","facebook","google","leetcode"], B = ["ec","oc","ceo"]
输出:["facebook","leetcode"]
注意
1 <= A.length, B.length <= 10000
1 <= A[i].length, B[i].length <= 10
A[i]
和B[i]
只由小写字母组成。A[i]
中所有的单词都是独一无二的,也就是说不存在i != j
使得A[i] == A[j]
。
算法
(枚举) $O(L(B.length + A.length))$
- 开一个长度为 26 的数组 letters,记录每个字母最少需要出现多少次才能满足
subset
的要求。直接枚举每个 B 中的单词,然后更新这个数组。 - 枚举每个 A 中的单词 a,同样统计出 a 中每个字母出现的次数,如果每个字母出现的次数都大于等于 letters 中对应字母出现的次数,则成功。
时间复杂度
- 假设 $L$ 为单词的平均长度,更新 letters 数组需要 $O(L \times B.length)$ 的时间;
- 枚举每个 A 中的单词并检查同样需要 $O(L \times A.length)$ 的时间;
- 故总时间复杂度为 $O(L(B.length + A.length))$。
空间复杂度
- 长度为 26 的数组空间占用为常数;
- 需要一个长度为 $O(A.length)$ 的数组用来统计答案;
- 故总时间复杂度为 $O(A.length)$。
C++ 代码
class Solution {
public:
bool check(const string &a, const vector<int>& letters) {
vector<int> l(26, 0);
for (auto c : a)
l[c - 'a']++;
for (int i = 0; i < 26; i++)
if (l[i] < letters[i])
return false;
return true;
}
vector<string> wordSubsets(vector<string>& A, vector<string>& B) {
vector<string> ans;
vector<int> letters(26, 0);
for (auto &b : B) {
vector<int> l(26, 0);
for (auto c : b)
l[c - 'a']++;
for (int i = 0; i < 26; i++)
letters[i] = max(letters[i], l[i]);
}
for (auto &a : A)
if (check(a, letters))
ans.push_back(a);
return ans;
}
};