1178.ワードパズル
外国人の友達が中国語の単語パズルをベースにした英語版の単語推測ゲームをデザインしました。ぜひ推測してみてください。
パズルファンは、次の2つの条件がpuzzle
あればword
、単語が与えられた文字列に直面し、それが答えとして数えられます。
- 単語
word
にはpuzzle
最初の文字のなぞなぞが含まれています。 word
なぞなぞの各文字の単語はpuzzle
にあります。
たとえば、パズルのなぞなぞがである場合、"abcdefg"
答えの単語"faced"
が"cabbage"
あり"baggage"
、; while "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]
文字には繰り返しが含まれていません。
方法1:状態の圧縮+列挙
問題解決のアイデア
この問題に対する暴力的な解決策を想像するのは難しいことではありません。各謎puzzle
はwords
解決するためにトラバースに行きます。
ヒントによると、パズルの顔10^4
の最大値、パズルの最大値は、10^5
一緒10^9
に乗算すると、間違いなくタイムアウトになります。
したがって、他の解決策を検討する必要があります。
- ヒントによると、パズルの顔と答えの両方に小文字しか含まれておらず、繰り返される文字は気にしません。なぞなぞや謎については、文字があったかどうかだけを気にするので、
26
ビットbit
を文字列化して、左から右に、それぞれ値0の文字z
がa
表示されないことを示し、1が表示されることを表すことができます。 - JavaのIntには32ビットがあり、intの最後の26ビットを直接使用して文字列を表すことができます。
上記の圧縮プロセスを理解した後、特定の実装手順を見てみましょう。
- まず、回答
words
デジタル、異なる文字列にはword
、このような同じ番号、になるかもしれない“ab”
し、“aaabbb”
デジタルすべてに3
。したがって、各番号の頻度を数えるためにマップが必要です。 - パズルの表面
puzzles
をトラバースし、同じ方法でパズルの表面を数字に変えます。ヒントによると、パズルの顔には7ビットしかありません。つまり、変換された数値の2進ビットには7ビットしかありません。我々ができ列挙するすべてのサブセット(2 7であれば、どのようなサブセットとしてのために、 - 1)最初の文字が含まれており、存在がマップに有効です。
詳細:
subnum = (subnum - 1) & bitnum
bitnum
すべてのサブセットを列挙するために、このコード描画を理解するようにしてください。
参照コード
public List<Integer> findNumOfValidWords(String[] words, String[] puzzles) {
// 把 words 中的字符串转为数字,并统计数字的出现次数。
Map<Integer, Integer> freq = new HashMap<>();
for (String word : words) {
int bitnum = getBitnum(word);
freq.put(bitnum, freq.getOrDefault(bitnum, 0) + 1);
}
List<Integer> ans = new ArrayList<>();
for (String puzzle : puzzles) {
int bitnum = getBitnum(puzzle);
int first = 1 << (puzzle.charAt(0) - 'a');
int subnum = bitnum;
int count = 0;
// 枚举谜面的所有子集:包含首字母 && map中存在
while (subnum > 0) {
if ((subnum & first) > 0 && freq.containsKey(subnum)) {
count += freq.get(subnum);
}
subnum = (subnum - 1) & bitnum;
}
ans.add(count);
}
return ans;
}
public Integer getBitnum(String s) {
int bitnum = 0;
for (char ch : s.toCharArray()) {
bitnum |= (1 << (ch - 'a'));
}
return bitnum;
}
の結果