博客
关于我
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 用 limit 为什么会影响性能?有什么优化方案?
查看>>
MySQL 用户权限管理:授权、撤销、密码更新和用户删除(图文解析)
查看>>
mysql 用户管理和权限设置
查看>>
MySQL 的 varchar 水真的太深了!
查看>>
mysql 的GROUP_CONCAT函数的使用(group_by 如何显示分组之前的数据)
查看>>
MySQL 的instr函数
查看>>
MySQL 的mysql_secure_installation安全脚本执行过程介绍
查看>>
MySQL 的Rename Table语句
查看>>
MySQL 的全局锁、表锁和行锁
查看>>
mysql 的存储引擎介绍
查看>>
MySQL 的存储引擎有哪些?为什么常用InnoDB?
查看>>
Mysql 知识回顾总结-索引
查看>>
Mysql 笔记
查看>>
MySQL 精选 60 道面试题(含答案)
查看>>
mysql 索引
查看>>
MySQL 索引失效的 15 种场景!
查看>>
MySQL 索引深入解析及优化策略
查看>>
MySQL 索引的面试题总结
查看>>
mysql 索引类型以及创建
查看>>
MySQL 索引连环问题,你能答对几个?
查看>>