题目链接:https://leetcode-cn.com/problems/number-of-valid-words-for-each-puzzle/
题意:
外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧。
字谜的迷面
puzzle
按字符串形式给出,如果一个单词word
符合下面两个条件,那么它就可以算作谜底:
- 单词
word
中包含谜面puzzle
的第一个字母。- 单词
word
中的每一个字母都可以在谜面puzzle
中找到。
例如,如果字谜的谜面是 "abcdefg",那么可以作为谜底的单词有 "faced", "cabbage", 和 "baggage";而 "beefed"(不含字母 "a")以及 "based"(其中的 "s" 没有出现在谜面中)都不能作为谜底。返回一个答案数组
answer
,数组中的每个元素answer[i]
是在给出的单词列表words
中可以作为字谜迷面puzzles[i]
所对应的谜底的单词数目。
方法一:哈希表暴力,会超时
class Solution {
public:
vector<int> findNumOfValidWords(vector<string>& words, vector<string>& puzzles) {
vector<int> ret,puzzle(26,0);//返回的向量,puzzle哈希表
unordered_map<char,int> mp;
char first = ' ';//首个字母
for(auto& str:puzzles)//遍历每一条灯谜
{
int len = str.size();//记录长度
first = str[0];
for(int i=0;i<len;i++)//更新puzzle哈希表
{
mp[str[i]]++;
}
int cnt = 0;//记录下满足条件的谜底个数
//遍历每个word,寻找谜底
for(auto& word:words)
{
int flag = 0;//记录word是否包含谜面puzzle的第一个字母
len = word.size();
int i;
for(i=0;i<len;i++)
{
if(word[i]==first)
{
flag = 1;
}
if(mp[word[i]]==0)
{
break;
}
}
if(i==len&&flag==1) cnt++;
}
ret.emplace_back(cnt);
mp.clear();
}
return ret;
}
};
方法二:位运算暴力,会超时
class Solution {
public:
vector<int> findNumOfValidWords(vector<string>& words, vector<string>& puzzles) {
vector<int> total;
int len = words.size();//统计谜底的个数
vector<int> mp(len,0);//哈希表,<在words中的序号,该字符串对应的掩码>,掩码就是用来进行异或,位,或,与运算,减少计算时间
int index = 0;
for(string& word:words)
{
int mask = 0;//掩码
for(char& ch:word)
mask |= 1<<(ch-'a');//按位或,掩码长度应该看作26位,因为有26个字母
mp[index] = mask;//更新哈希项
index++;//对应序号自加
}
for(string& puzzle:puzzles)//枚举每一个谜面
{
int cnt = 0;//计数谜底
for(int i=0;i<len;i++)//枚举谜底
{
//确认谜面的首字母在谜底中
int first = 1<<(puzzle[0]-'a');//记录谜面中的首个字母的二进制,然后与掩码与,看最后是不是仍然是first,是的话就说明在谜底中,然后再继续判断
if((first&mp[i])==first)
{
//确认谜面对应的掩码
int mask = 0;//掩码
for(char& ch:puzzle)
mask |= 1<<(ch-'a');//按位或,掩码长度应该看作26位,因为有26个字母
if((mask&mp[i])==mp[i])
cnt++;
}
}
total.emplace_back(cnt);
}
return total;
}
};
位运算,根据谜面的掩码往下进行枚举,另一种暴力,不会超时
思路与982. 按位与为零的三元组(双百解法)一致
class Solution {
public:
vector<int> findNumOfValidWords(vector<string>& words, vector<string>& puzzles) {
vector<int> total;
int len = words.size();//统计谜底的个数
unordered_map<int,int> mp;//哈希表,<该字符串对应的掩码,出现的次数>,掩码就是用来进行异或,位,或,与运算,减少计算时间
int index = 0;
for(string& word:words)
{
int mask = 0;//掩码
for(char& ch:word)
mask |= 1<<(ch-'a');//按位或,掩码长度应该看作26位,因为有26个字母
mp[mask]++;//更新哈希项
}
for(string& puzzle:puzzles)//枚举每一个谜面
{
int cnt = 0;
//求出puzzle的掩码
int mask = 0;//掩码
for(char& ch:puzzle)
mask |= 1<<(ch-'a');//按位或,掩码长度应该看作26位,因为有26个字母
//确认首字符的掩码
int first = 1<<(puzzle[0]-'a');
for(int i=mask;i!=0;i=((i-1)&mask))
{
//如果谜底不包括谜面的首字符就跳过
if((first&i)!=first) continue;
cnt+=mp[i];//是谜底就累加
}
total.emplace_back(cnt);
}
return total;
}
};