Leetcode 1178. Number of Valid Words for Each Puzzle
Woodyiiiiiii opened this issue · comments
1178. Number of Valid Words for Each Puzzle
1178. Number of Valid Words for Each Puzzle
这道题我一开始发现每个word其字母排序、字母出现次数不重要,所以我的初步想法是:将每个word放入treeset中去重排序,再对每个puzzle也去重排序,然后对比,对于每个puzzle其是多少个word的前缀。(其实单个的word或者puzzle已经长度很小已经暗示了要对其中之一缓存)
接下来我一下子想到了字典树Trie。但问题是,是将word还是puzzle放入字典树里呢?按常理来说,应该放入words,这样遍历puzzles才能知道每个puzzle是多少个word的前缀,但这就违反了字典树的定义了——判断字符串是不是字典树里的前缀;反之,放入puzzles,遍历words,就算知道每个word是多少个puzzles的前缀,那该如何定位这几个puzzles呢,因为最后求的是puzzles对应的结果。
看了题解才知道,这需要放弃Trie,用状压bitmask来记录位置。我练习的bitmask类型题目还不多,所以还没这么敏感,遇到这类状态之间互不干扰且较小的题目可以用bitmask考虑。
正解:遍历words,状态压缩,然后用哈希表记录每个整数值和数量;然后遍历puzzles,同样对于每个puzzle状压得到对应的整数;
接下来是第二个难点(第一个是想到状压):如何通过puzzle对应的二进制数找到所以满足其子集的words呢?通过(sub-1)&mask
不断向下遍历,然后通过记录的map找到个数。对于是否包含第一个字符,则加个判断即可。
时间复杂度:O( n * 2 ^ 7 + m * k) = O(n + mk)
class Solution {
public List<Integer> findNumOfValidWords(String[] words, String[] puzzles) {
Map<Integer, Integer> cntMap = new HashMap<>();
for (String word : words) {
int mask = 0;
for (char c : word.toCharArray()) {
mask |= 1 << (c - 'a');
}
cntMap.put(mask, cntMap.getOrDefault(mask, 0) + 1);
}
List<Integer> res = new ArrayList<>();
for (String puzzle : puzzles) {
char first = puzzle.charAt(0);
int firstMask = 1 << (first - 'a');
int mask = 0;
for (char c : puzzle.toCharArray()) {
mask |= 1 << (c - 'a');
}
int p = mask;
int cnt = 0;
while (p > 0) {
if ((p & firstMask) > 0 && cntMap.containsKey(p)) {
cnt += cntMap.get(p);
}
p = (p - 1) & mask;
}
res.add(cnt);
}
return res;
}
}
func findNumOfValidWords(words []string, puzzles []string) []int {
// cache with bit mask
wordsMap := make(map[int]int)
for _, word := range words {
mask := 0
for _, ch := range word {
mask |= 1 << (ch - 'a')
}
wordsMap[mask]++
}
res := make([]int, 0)
for _, puzzle := range puzzles {
mask := 0
for _, ch := range puzzle {
mask |= 1 << (ch - 'a')
}
subInt := mask
firstC := puzzle[0]
firstMask := 1 << (firstC - 'a')
cnt := 0
for ; subInt > 0; subInt = (subInt - 1) & mask {
if subInt&firstMask > 0 {
cnt += wordsMap[subInt]
}
}
res = append(res, cnt)
}
return res
}