情况
你有一个字典(文件)和一个包含一个或多个单词的字谜。字谜不包含原始单词的任何标点符号或字母大小写。
现在您想找到所有真正的解决方案,在这些解决方案中,您用完字谜的所有字符并将其解码为字典中的单词。
注意:您可能会找到多种解决方案,但您永远不会知道原始文本是哪一个以及单词的顺序,因为多个单词的字符混合在字谜并且您没有标点符号或其中的字母大小写。
您的代码
您当前代码中的问题正是您将多个单词混合在一起。如果您现在对它们进行排序,并且想在字典中搜索它们,您将无法找到它们,因为多个单词的字符混合在一起。示例:
anagram = "oatdgc" //"cat" + "dog"
wordList = ["cat", "dog"]
wordListSorted = ["act", "dgo"]
anagramSorted = acdgot
↓↓↓
WordListSorted[0] → cat ✗ no match
WordListSorted[1] → dog ✗ no match
解决方案
首先我将在理论上解释我们如何构建所有可能的真实解决方案,然后我会解释代码中的每个部分是如何工作的。
理论
首先我们有一个字谜和字典。现在我们首先通过字谜过滤字典,只保留字词,可以由字谜构造。
然后我们遍历所有单词,并将每个单词添加到一个可能的解决方案中,将其从 anagram 中删除,通过新 anagram 过滤字典并递归调用具有新值的函数。
我们这样做直到字谜为空并且我们找到了一个真正的解决方案,我们将其添加到我们的解决方案集合中,或者没有剩余的单词并且它不是一个可能的解决方案。
代码
我们的代码中有两个辅助函数 array_diff_once() 和 preSelectWords()。
array_diff_once() 与内置的array_diff() 函数几乎相同,只是它只删除一次而不是所有出现的值。否则没有太多可解释的。它只是遍历第二个数组,并在第一个数组中删除一次值,然后返回。
function array_diff_once($arrayOne, $arrayTwo){
foreach($arrayTwo as $v) {
if(($key = array_search($v, $arrayOne)) !== FALSE)
array_splice($arrayOne, $key, 1);
}
return $arrayOne;
}
preSelectWords() 将一个字谜和一个单词列表作为参数。它只是在array_diff_once() 的帮助下检查,可以使用给定的字谜构造单词列表中的哪些单词。然后它从单词列表中返回所有可能的单词,可以用字谜构造。
function preSelectWords($anagram, $wordList){
$tmp = [];
foreach($wordList as $word){
if(!array_diff_once(str_split(strtolower($word)), $anagram))
$tmp[] = $word;
}
return $tmp;
}
现在到主函数decodeAnagram()。我们将首先使用preSelectWords() 过滤的字谜和单词列表作为参数传递给函数。
在函数本身中,我们基本上只是遍历单词,对于每个单词,我们将其从 anagram 中删除,通过新的 anagram 过滤单词列表并将单词添加到可能的解决方案中并递归调用函数。
我们这样做直到字谜为空并且我们找到了一个真正的解决方案,我们将其添加到我们的解决方案数组中,或者列表中没有留下任何单词并且没有可能的解决方案。
function decodeAnagram($anagram, $wordList, $solution, &$solutions = []){
if(empty($anagram) && sort($solution) && !isset($solutions[$key = implode($solution)])){
$solutions[$key] = $solution;
return;
}
foreach($wordList as $word)
decodeAnagram(array_diff_once($anagram, str_split(strtolower($word))), preSelectWords(array_diff_once($anagram, str_split(strtolower($word))), $wordList), array_merge($solution, [$word]), $solutions);
}
代码
<?php
function decodeAnagram($anagram, $wordList, $solution, &$solutions = []){
if(empty($anagram) && sort($solution) && !isset($solutions[$key = implode($solution)])){
$solutions[$key] = $solution;
return;
}
foreach($wordList as $word)
decodeAnagram(array_diff_once($anagram, str_split(strtolower($word))), preSelectWords(array_diff_once($anagram, str_split(strtolower($word))), $wordList), array_merge($solution, [$word]), $solutions);
}
function preSelectWords($anagram, $wordList){
$tmp = [];
foreach($wordList as $word){
if(!array_diff_once(str_split(strtolower($word)), $anagram))
$tmp[] = $word;
}
return $tmp;
}
function array_diff_once($arrayOne, $arrayTwo){
foreach($arrayTwo as $v) {
if(($key = array_search($v, $arrayOne)) !== FALSE)
array_splice($arrayOne, $key, 1);
}
return $arrayOne;
}
$solutions = [];
$anagram = "aaaeeehiikllmprssw";
$wordList = ["I", "am", "a", "weakish", "speller", "William", "Shakespeare", "other", "words", "as", "well"];
//↑ file("wordlist", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
decodeAnagram(str_split(strtolower($anagram)), preSelectWords(str_split(strtolower($anagram)), $wordList), [], $solutions);
print_r($solutions);
?>
输出
Array
(
[Iaamspellerweakish] => Array
(
[0] => I
[1] => a
[2] => am
[3] => speller
[4] => weakish
)
[ShakespeareWilliam] => Array
(
[0] => Shakespeare
[1] => William
)
)
(忽略这里的键,因为它们是解决方案的标识符)