英文原文
This is an interactive problem.
You are given an array of unique strings wordlist
where wordlist[i]
is 6
letters long, and one word in this list is chosen as secret
.
You may call Master.guess(word)
to guess a word. The guessed word should have type string
and must be from the original list with 6
lowercase letters.
This function returns an integer
type, representing the number of exact matches (value and position) of your guess to the secret
word. Also, if your guess is not in the given wordlist, it will return -1
instead.
For each test case, you have exactly 10
guesses to guess the word. At the end of any number of calls, if you have made 10
or fewer calls to Master.guess
and at least one of these guesses was secret
, then you pass the test case.
Example 1:
Input: secret = "acckzz", wordlist = ["acckzz","ccbazz","eiowzz","abcczz"], numguesses = 10 Output: You guessed the secret word correctly. Explanation: master.guess("aaaaaa") returns -1, because "aaaaaa" is not in wordlist. master.guess("acckzz") returns 6, because "acckzz" is secret and has all 6 matches. master.guess("ccbazz") returns 3, because "ccbazz" has 3 matches. master.guess("eiowzz") returns 2, because "eiowzz" has 2 matches. master.guess("abcczz") returns 4, because "abcczz" has 4 matches. We made 5 calls to master.guess and one of them was the secret, so we pass the test case.
Example 2:
Input: secret = "hamada", wordlist = ["hamada","khaled"], numguesses = 10 Output: You guessed the secret word correctly.
Constraints:
1 <= wordlist.length <= 100
wordlist[i].length == 6
wordlist[i]
consist of lowercase English letters.- All the strings of
wordlist
are unique. secret
exists inwordlist
.numguesses == 10
中文题目
这个问题是 LeetCode 平台新增的交互式问题 。
我们给出了一个由一些独特的单词组成的单词列表,每个单词都是 6 个字母长,并且这个列表中的一个单词将被选作秘密。
你可以调用 master.guess(word)
来猜单词。你所猜的单词应当是存在于原列表并且由 6 个小写字母组成的类型字符串
。
此函数将会返回一个整型数字
,表示你的猜测与秘密单词的准确匹配(值和位置同时匹配)的数目。此外,如果你的猜测不在给定的单词列表中,它将返回 -1
。
对于每个测试用例,你有 10 次机会来猜出这个单词。当所有调用都结束时,如果您对 master.guess
的调用不超过 10 次,并且至少有一次猜到秘密,那么您将通过该测试用例。
除了下面示例给出的测试用例外,还会有 5 个额外的测试用例,每个单词列表中将会有 100 个单词。这些测试用例中的每个单词的字母都是从 'a'
到 'z'
中随机选取的,并且保证给定单词列表中的每个单词都是唯一的。
示例 1: 输入: secret = "acckzz", wordlist = ["acckzz","ccbazz","eiowzz","abcczz"] 解释:master.guess("aaaaaa")
返回 -1, 因为"aaaaaa"
不在 wordlist 中.master.guess("acckzz") 返回
6, 因为"acckzz"
就是秘密,6个字母完全匹配。master.guess("ccbazz")
返回 3, 因为"ccbazz"
有 3 个匹配项。master.guess("eiowzz")
返回 2, 因为"eiowzz"
有 2 个匹配项。master.guess("abcczz")
返回 4, 因为"abcczz"
有 4 个匹配项。 我们调用了 5 次master.guess,其中一次猜到了秘密,所以我们通过了这个测试用例。
提示:任何试图绕过评判的解决方案都将导致比赛资格被取消。
通过代码
官方题解
方法 1:启发式极小化极大算法
想法
显然,可行单词列表中的单词越少越好。如果数据随机,那么我们可以认定这个情况是普遍的。
现在,利用极小化极大算法猜测可行的单词列表。如果我们开始有 $N$ 个单词,我们通过迭代去选择可行单词。
算法
存储 H[i][j]
为 wordlist[i]
和 wordlist[j]
单词匹配数。每次猜测要求之前没有猜过,按照上面的说法实现极小化极大算法,每次选择猜测的单词是当前可行单词中的一个。
class Solution {
int[][] H;
public void findSecretWord(String[] wordlist, Master master) {
int N = wordlist.length;
H = new int[N][N];
for (int i = 0; i < N; ++i)
for (int j = i; j < N; ++j) {
int match = 0;
for (int k = 0; k < 6; ++k)
if (wordlist[i].charAt(k) == wordlist[j].charAt(k))
match++;
H[i][j] = H[j][i] = match;
}
List<Integer> possible = new ArrayList();
List<Integer> path = new ArrayList();
for (int i = 0; i < N; ++i) possible.add(i);
while (!possible.isEmpty()) {
int guess = solve(possible, path);
int matches = master.guess(wordlist[guess]);
if (matches == wordlist[0].length()) return;
List<Integer> possible2 = new ArrayList();
for (Integer j: possible) if (H[guess][j] == matches) possible2.add(j);
possible = possible2;
path.add(guess);
}
}
public int solve(List<Integer> possible, List<Integer> path) {
if (possible.size() <= 2) return possible.get(0);
List<Integer> ansgrp = possible;
int ansguess = -1;
for (int guess = 0; guess < H.length; ++guess) {
if (!path.contains(guess)) {
ArrayList<Integer>[] groups = new ArrayList[7];
for (int i = 0; i < 7; ++i) groups[i] = new ArrayList<Integer>();
for (Integer j: possible) if (j != guess) {
groups[H[guess][j]].add(j);
}
ArrayList<Integer> maxgroup = groups[0];
for (int i = 0; i < 7; ++i)
if (groups[i].size() > maxgroup.size())
maxgroup = groups[i];
if (maxgroup.size() < ansgrp.size()) {
ansgrp = maxgroup;
ansguess = guess;
}
}
}
return ansguess;
}
}
class Solution(object):
def findSecretWord(self, wordlist, master):
N = len(wordlist)
self.H = [[sum(a==b for a,b in itertools.izip(wordlist[i], wordlist[j]))
for j in xrange(N)] for i in xrange(N)]
possible, path = range(N), ()
while possible:
guess = self.solve(possible, path)
matches = master.guess(wordlist[guess])
if matches == len(wordlist[0]): return
possible = [j for j in possible if self.H[guess][j] == matches]
path = path + (guess,)
def solve(self, possible, path = ()):
if len(possible) <= 2: return possible[0]
ansgrp, ansguess = possible, None
for guess, row in enumerate(self.H):
if guess not in path:
groups = [[] for _ in xrange(7)]
for j in possible:
if j != guess:
groups[row[j]].append(j)
maxgroup = max(groups, key = len)
if len(maxgroup) < len(ansgrp):
ansgrp, ansguess = maxgroup, guess
return ansguess
复杂度分析
- 时间复杂度:$O(N^2 \log{N})$,其中 $N$ 是单词的总数,假设其长度为 $O(1)$。每调用一次
solve
是 $O(N)$,调用次数的上界为 $O(\log N)$。 - 空间复杂度:$O(N^2)$。
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
3000 | 7805 | 38.4% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|