leetcode1178. 猜字谜

题目链接: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;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值