import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** leetcode: 1178.猜字谜* <p>* 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧。* <p>* 字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件,那么它就可以算作谜底:* <p>* 单词 word 中包含谜面 puzzle 的第一个字母。* 单词 word 中的每一个字母都可以在谜面 puzzle 中找到。* 例如,如果字谜的谜面是 "abcdefg",那么可以作为谜底的单词有 "faced", "cabbage", 和 "baggage";而 "beefed"(不含字母 "a")以及 "based"(其中的 "s" 没有出现在谜面中)。* 返回一个答案数组 answer,数组中的每个元素 answer[i] 是在给出的单词列表 words 中可以作为字谜迷面 puzzles[i] 所对应的谜底的单词数目。* <p>* 输入:* 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'。** @Author: xiaofeifei* @Date: 2021/2/26 10:49*/
public class FindNumOfValidWords {public static void main(String[] args) {// System.out.println(findNumOfValidWords(new String[]{"aaaa", "asas", "able", "ability", "actt", "actor", "access"}, new String[]{"aboveyz", "abrodyz", "abslute", "absoryz", "actresz", "gaswxyz"}));System.out.println(findNumOfValidWords1(new String[]{"aaaa", "asas", "able", "ability", "actt", "actor", "access"}, new String[]{"aboveyz", "abrodyz", "abslute", "absoryz", "actresz", "gaswxyz"}));}public static boolean contains(String puzzle, Set<String> set) {// 1. word 中的字母必须包含puzzle的首字母if (!set.contains(String.valueOf(puzzle.charAt(0)))) {return false;}// 2. word 中的每个字母必须在puzzle中有所包含for (String s : set) {if (!puzzle.contains(s)) {return false;}}return true;}/*** 思路:* 1. word 中的字母必须包含puzzle的首字母* 2. word 中的每个字母必须在puzzle中有所包含* 3. puzzles[i].length == 7 => 表示puzzle的长度固定为7* 4. 每个 puzzles[i] 所包含的字符都不重复* <p>* 对word进行字母去重 然后相互比较* <p>* <p>* 这种方法可以实现 但是不能满足leetcode自身的执行时间限制** @param words* @param puzzles* @return*/public static List<Integer> findNumOfValidWords(String[] words, String[] puzzles) {int[] result = new int[puzzles.length];int puzzleLen = puzzles.length;List<String> puzzleCharList = Stream.of(puzzles).map(puzzle -> String.valueOf(puzzle.charAt(0))).collect(Collectors.toList());List<Set<String>> wordList = Stream.of(words).filter(word -> {for (String puzzleFirst : puzzleCharList) {if (word.contains(puzzleFirst)) {return true;}}return false;}).map(word -> {char[] charArr = word.toCharArray();// 校验是否满足第一个条件// 去重处理Set<String> set = new HashSet<>(charArr.length);for (char ch : charArr) {set.add(String.valueOf(ch));}return set;}).collect(Collectors.toList());// 对puzzles进行排序for (int p = 0; p < puzzleLen; p++) {for (Set<String> strings : wordList) {if (contains(puzzles[p], strings)) {result[p]++;}}}ArrayList<Integer> nums = new ArrayList<>(puzzles.length);for (int num : result) {nums.add(num);}return nums;}/*** leetcode 官方解答:* <p>* 因为都是小写字母 所以可以用0 -> 25位来表示 a -> z* <p>* a => 97 所以将字符转为整型 再减去a则得到具体的值 然后转换成二进制** @param words* @param puzzles* @return*/public static List<Integer> findNumOfValidWords1(String[] words, String[] puzzles) {// 用来记录words的表示集合 方便后续存取List<Integer> result = new ArrayList<>(puzzles.length);Map<Integer, Integer> frequency = new HashMap<>();for (String word : words) {// mask用来表示word的二进制表示形式比如说abcdefg => 0111 1111int mask = 0;for (int i = 0; i < word.length(); i++) {char ch = word.charAt(i);// 比如说ch为c=3 1 << 3 => 0000 1000// 这样即使字符出现重复 二进制的方式也完美解决了重复问题mask |= 1 << (ch - 'a');}// 获取二进制中1的数量 如果数量大于7 则它一定不会成为谜底 因为谜面本身就只有7位if (Integer.bitCount(mask) <= 7) {// 这里很关键哈,key用来记录word的二进制表示,value用来记录word的出现次数// 也就是是否重复了,相同的word则value就+1frequency.put(mask, frequency.getOrDefault(mask, 0) + 1);}}// 同理 将puzzles 也转换成二进制表示信息 肯定是7个1 puzzles本身// 然后再遍历中直接比较for (String puzzle : puzzles) {// 记录当前谜面匹配次数int total = 0;int mask = 0;// 这里请注意,这里获取到的mask是6位 不包含最高位// 因为最高位就是第一个字符,这里获取的是后6位的值// 一般认为应该是遍历7次 这里只使用6次循环的好处是 降低了执行时间成本for (int i = 1; i < puzzle.length(); i++) {mask |= (1 << (puzzle.charAt(i) - 'a'));}// 6个1 的puzzle 不包含最高位int subset = mask;do {// firstBit 用于表示puzzle的首字母int firstBit = 1 << (puzzle.charAt(0) - 'a');// 获取最后真实的puzzle的二进制int s = subset | firstBit;if (frequency.containsKey(s)) {total += frequency.get(s);}// 这里是核心// 比如说 puzzle 为 0111 1111// 因为最高位必须要满足 所以只需要比较6位为 0011 1111// 所以6为的子集为 2^7 - 1 & mask(0011 1111) -> 不包含 -1 & mask(0011 1111)这么多种可能// 然后加上首字母 组成二进制 判断frequency是否包含 包含则匹配成功 返回// 不包含则继续获取子集 直到获取的subset 为 0 即(subset - 1) = -1// -1 & mask = mask 所以当subset == mask时// 则应该跳出循环 至此 所以子集匹配结束// 这里的思想很聪明 跳过了 puzzles * words的遍历导致时间复杂度{O{M*N}}过大的问题// 而是转而利用二进制的本身机制 反向通过puzzle的二进制表示形式来反推其所有满足的子集是否存在于// words所表示的hashMap中,hashMap本身的散列机制,检索效率很快。// 因此它的时间复杂度要远远小于直接遍历判断的问题// (subset - 1) & mask 保证了其结果肯定为mask的子集 结果为负则子集遍历结束subset = (subset - 1) & mask;// 所以当subset == mask时会退出// 这里为什么不判断subset > 0 就好了呢,因此存在首字母// 因为subset是6个1 ,还有一个首字母 如果word就只包含首字母呢 则当subset为0时// 也是可以满足条件的,只有当subset = -1时才应该跳出循环} while (subset != mask);result.add(total);}return result;}
}

记录一下leetcode:1178猜字谜相关推荐

  1. leetcode 1178.猜字谜

    leetcode 1178.猜字谜 题干 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧. 字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件,那么 ...

  2. leetcode 1178. 猜字谜(位运算)

    外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧. 字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件,那么它就可以算作谜底: 单词 word 中包含 ...

  3. LeetCode 1178. 猜字谜(状态压缩+枚举二进制子集+哈希)

    文章目录 1. 题目 2. 解题 1. 题目 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧. 字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件, ...

  4. 【力扣】1178. 猜字谜

    以下为力扣官方题解 1178. 猜字谜 题目 示例 提示 官方题解 前言 方法一 二进制状态压缩 思路与算法 细节 代码 复杂度分析 方法二:字典树 思路与算法 细节 代码 复杂度分析 题目 外国友人 ...

  5. leetcode 1178. Number of Valid Words for Each Puzzle | 1178. 猜字谜(bitmask位运算)

    题目 https://leetcode.com/problems/number-of-valid-words-for-each-puzzle/ 题解 看了答案,堪称力扣最详细的答案,从时间复杂度的角度 ...

  6. 猜字谜 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧。 字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件,那么它就可以算作谜底:

    今天是元宵节,力扣也细心地为我们准备了一道有关节日的题,一起看看吧: 1178. 猜字谜 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧. 字谜的迷面 puzzle 按字符串形式给出 ...

  7. Leetcode 猜字谜

    WechatIMG521.jpeg 题目描述 leetcode 第1178题:猜字谜 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧. 字谜的迷面 puzzle 按字符串形式给出,如 ...

  8. LeetCode日记_007_猜字谜

    题目信息: 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧. 字谜的迷面puzzle 按字符串形式给出,如果一个单词word符合下面两个条件,那么它就可以算作谜底: 单词word中包 ...

  9. 算法--猜字谜(哈希表优化)

    算法–猜字谜(哈希表优化) 元宵节的时候,力扣上的每日一题是这样的: 外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧. 字谜的迷面 puzzle 按字符串形式给出,如果一个单词 wo ...

最新文章

  1. 经典不过时,回顾DeepCompression神经网络压缩
  2. JSON 数据格式解析(转)
  3. python3下载慢-PIP 下载慢,给你Python3的pip换个源 一键换源
  4. BOOST_PREDEF_WORKAROUND宏相关的测试程序
  5. 川大计算机高考分数,2020年四川大学录取分数是多少 2020年高考多少分可以报考四川大学...
  6. 解决import tensorflow时的报错 Passing (type, 1) or ‘1type‘ as a synonym of type is deprecate
  7. PKU 学生反馈 3
  8. MFC设置对话框背景色及控件颜色
  9. mysql 表死锁_MySQL Innodb表导致死锁日志情况分析与归纳
  10. SpringData环境搭建代码编写
  11. 小程序毕设作品之微信小程序点餐系统毕业设计(5)任务书
  12. 如何快速实现一个抽签小程序
  13. 介绍一款通过软件设置调节显示器亮度的工具:护眼宝
  14. 选择什么语言真的重要吗
  15. PS获取图片三种方式
  16. 微信小程序 家校通 中小学家校联系电子作业系统
  17. MQTT连接阿里云物联网平台步骤
  18. int类型以及指针的类型所占字节的大小,到底是由什么决定的?
  19. 如何在 Linux 服务器上安装 Red5?
  20. 十四年磨一剑,万能数据库查询分析器7.024版本 发布

热门文章

  1. Redis INCR数值操作命令
  2. 什么是分账系统为什么要用分账系统
  3. 手动备份安卓手机的基本流程
  4. 游戏大厅 从基础开始(3)——最吸引眼球的部分 客户端与服务器的连接
  5. Linux - ps -aux详细解释
  6. 写方案字数越多越好写
  7. 网络电话变身情趣APP 体验通话更多乐趣
  8. 知道怎么体重变轻吗?
  9. 云应用的概念、特性及部署
  10. Kotlin报错:Out-projected type ... prohibits the use of ... defined in ...的解决方案