博客
关于我
leetcode 1178.猜字谜
阅读量:667 次
发布时间:2019-03-15

本文共 4943 字,大约阅读时间需要 16 分钟。

leetcode 1178.猜字谜

题干

外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧。

字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件,那么它就可以算作谜底:
单词 word 中包含谜面 puzzle 的第一个字母。
单词 word 中的每一个字母都可以在谜面 puzzle 中找到。
例如,如果字谜的谜面是 “abcdefg”,那么可以作为谜底的单词有 “faced”, “cabbage”, 和 “baggage”;而 “beefed”(不含字母 “a”)以及 “based”(其中的 “s” 没有出现在谜面中)。
返回一个答案数组 answer,数组中的每个元素 answer[i] 是在给出的单词列表 words 中可以作为字谜迷面 puzzles[i] 所对应的谜底的单词数目。

示例:

输入:
words = [“aaaa”,“asas”,“able”,“ability”,“actt”,“actor”,“access”],
puzzles = [“aboveyz”,“abrodyz”,“abslute”,“absoryz”,“actresz”,“gaswxyz”]
输出:[1,1,3,2,4,0]
解释:
1 个单词可以作为 “aboveyz” 的谜底 : “aaaa”
1 个单词可以作为 “abrodyz” 的谜底 : “aaaa”
3 个单词可以作为 “abslute” 的谜底 : “aaaa”, “asas”, “able”
2 个单词可以作为 “absoryz” 的谜底 : “aaaa”, “asas”
4 个单词可以作为 “actresz” 的谜底 : “aaaa”, “asas”, “actt”, “access”
没有单词可以作为 “gaswxyz” 的谜底,因为列表中的单词都不含字母 ‘g’。

提示:

1 <= words.length <= 10^5
4 <= words[i].length <= 50
1 <= puzzles.length <= 10^4
puzzles[i].length == 7
words[i][j], puzzles[i][j] 都是小写英文字母。
每个 puzzles[i] 所包含的字符都不重复。

题解

直接模拟,用数组映射26个字母的出现次数,显然超时了

class Solution {   public:    vector
findNumOfValidWords(vector
& words, vector
& puzzles) { int puzzleCount = puzzles.size(); int wordCount = words.size(); vector
> puzzleStat(puzzleCount,vector
(26,0)); vector
> wordStat(wordCount,vector
(26,0)); vector
ans(puzzleCount); for(int i = 0 ; i < puzzleCount ; ++i){ for(auto j : puzzles[i]){ puzzleStat[i][j - 'a']++; } } for(int i = 0 ; i < wordCount ; ++i){ for(auto j : words[i]){ wordStat[i][j - 'a']++; } } for(int i = 0 ; i < puzzleCount ; ++i){ int ansCount = 0; for(int j = 0 ; j < wordCount ; ++j){ //如果j标words中有谜面的首字母 if(wordStat[j][puzzles[i][0] - 'a'] != 0){ bool flag = true; for(int k = 0 ; k < 26 ; ++k){ //如果j标words中存在的字母在谜面中bu存在 if(wordStat[j][k] != 0 && puzzleStat[i][k] == 0){ flag = false; break; } } if(flag){ ansCount++; } } } ans[i] = ansCount; } return ans; }};

思考一下位运算的可能性,2^26 = 67108864 < INT_MAX

那好办,就不用数组映射字母出现次数了,用一个二进制int来映射就行,因为题目要求的判别并不用判断字母的个数,只要能够表示是否存在就可以了
还就那个继续超时

class Solution {   public:    //获取num从右往左第n位    int getDigit(int num,int n){           num >>= n;        return num & 1;    }    vector
findNumOfValidWords(vector
& words, vector
& puzzles) { int puzzleCount = puzzles.size(); int wordCount = words.size(); vector
puzzleStat(puzzleCount,0); vector
wordStat(wordCount,0); vector
ans(puzzleCount); for(int i = 0 ; i < puzzleCount ; ++i){ int tempCount = 0; for(auto j : puzzles[i]){ puzzleStat[i] |= 1 << (j - 'a'); } } for(int i = 0 ; i < wordCount ; ++i){ for(auto j : words[i]){ wordStat[i] |= 1 << (j - 'a'); } } for(int i = 0 ; i < puzzleCount ; ++i){ int ansCount = 0; for(int j = 0 ; j < wordCount ; ++j){ //如果j标words中有谜面的首字母 //out<

那就只能反过来遍历了,根据谜面枚举谜面的所有二进制子集(因为谜面只有7位),然后把words对应的二进制信息放到哈希表中,通过谜面二进制的子集元素来检查哈希表

class Solution {   public:    vector
findNumOfValidWords(vector
& words, vector
& puzzles) { int puzzleCount = puzzles.size(); int wordCount = words.size(); unordered_map
wordsMask; vector
ans(puzzleCount,0); for(int i = 0 ; i < wordCount ; ++i){ int tempMask = 0; for(auto j : words[i]){ tempMask |= 1 << (j - 'a'); } if (__builtin_popcount(tempMask) <= 7) { wordsMask[tempMask]++; } } for(int i = 0 ; i < puzzleCount ; ++i){ int sum = 0; int puzzlesMask = 0; for(auto j : puzzles[i]){ puzzlesMask |= 1 << (j - 'a'); } int tempMask = puzzlesMask; do{ int index = tempMask | (1 << (puzzles[i][0] - 'a') ); if(wordsMask.count(index)){ sum += wordsMask[index]; } tempMask = (tempMask - 1) & puzzlesMask; }while(tempMask != puzzlesMask); ans[i] = sum / 2; } return ans; }};

关键还就是这手二进制子集遍历:

int tempMask = puzzlesMask;            do{                   int index = tempMask | (1 << (puzzles[i][0] - 'a') );                if(wordsMask.count(index)){                       sum += wordsMask[index];                }                tempMask = (tempMask - 1) & puzzlesMask;            }while(tempMask != puzzlesMask);

有点写呲了,这里我的写法把整个谜面取进了mask,导致在后面遍历子集的时候连带着首位的1在遍历,结果就是统计个数翻了一番。

for(auto j : puzzles[i]){                   puzzlesMask |= 1 << (j - 'a');            }

这里如果改写成下标,不取第一位的话,后面sum就不用/2了

for(int j = 1 ; j < 7 ; ++j){                   puzzlesMask |= 1 << (puzzles[i][j] - 'a');            }

转载地址:http://wnqmz.baihongyu.com/

你可能感兴趣的文章
mysql 常用
查看>>
MySQL 常用列类型
查看>>
mysql 常用命令
查看>>
Mysql 常见ALTER TABLE操作
查看>>
MySQL 常见的 9 种优化方法
查看>>
MySQL 常见的开放性问题
查看>>
Mysql 常见错误
查看>>
mysql 常见问题
查看>>
MYSQL 幻读(Phantom Problem)不可重复读
查看>>
mysql 往字段后面加字符串
查看>>
mysql 快速自增假数据, 新增假数据,mysql自增假数据
查看>>
Mysql 批量修改四种方式效率对比(一)
查看>>
Mysql 报错 Field 'id' doesn't have a default value
查看>>
MySQL 报错:Duplicate entry 'xxx' for key 'UNIQ_XXXX'
查看>>
Mysql 拼接多个字段作为查询条件查询方法
查看>>
mysql 排序id_mysql如何按特定id排序
查看>>
Mysql 提示:Communication link failure
查看>>
mysql 插入是否成功_PDO mysql:如何知道插入是否成功
查看>>
Mysql 数据库InnoDB存储引擎中主要组件的刷新清理条件:脏页、RedoLog重做日志、Insert Buffer或ChangeBuffer、Undo Log
查看>>
mysql 数据库中 count(*),count(1),count(列名)区别和效率问题
查看>>