所以我试图将字谜解码为我的字典文件中的单词。但是我的递归函数并不像我期待的那样表现。
关于代码的想法是消除在单词上使用的字母,并输出它出现的字符串。
<?php
function anagram($string, $wordlist)
{
if(empty($string))
return;
foreach($wordlist as $line)
{
$line = $org = trim($line);
$line = str_split($line);
sort($line);
foreach($line as $key => $value)
{
if($value != $string[$key])
{
continue 2;
}
}
echo $org . anagram(array_slice($string, count($line)), $wordlist);
}
echo PHP_EOL;
}
$string = "iamaweakishspeller";
$string = str_split($string);
sort($string);
$file = file('wordlist');
anagram($string, $file);
这是我现在的结果,它看起来很糟糕,但我在代码中遇到了一些问题 - 它会进入一个无限循环,其中大约有200个字来自单词列表。
有人可以在此处加倍吗?
答案 0 :(得分:3)
你有一个字典(文件)和一个包含一个或多个单词的字谜。字谜不包含原始单词的任何标点符号或字母。
现在你想要找到所有真正的解决方案,你用掉字谜的所有字符并将其解码为字典中的单词。
注意:您可能会找到多个解决方案,而且您永远不会知道原始文本是哪一个以及单词的顺序,因为多个单词的字符混合在一起字谜,你没有标点符号或字母的情况。
您当前代码中的问题恰恰在于您将多个单词混合在一起。如果你现在对它们进行排序,并且你想在字典中搜索它们,你将无法找到它们,因为多个单词的字符是混合的。例如:
anagram = "oatdgc" //"cat" + "dog"
wordList = ["cat", "dog"]
wordListSorted = ["act", "dgo"]
anagramSorted = acdgot
↓↓↓
WordListSorted[0] → cat ✗ no match
WordListSorted[1] → dog ✗ no match
首先,我将在理论上解释我们如何构建所有可能的真正解决方案,然后解释代码中的每个部分是如何工作的。
首先,我们有一个字谜和字典。现在我们首先用字谜过滤字典,只保留可以用字谜构建的单词。
然后我们浏览所有单词,对于每个单词,我们将其添加到可能的解决方案中,将其从anagram中删除,通过新的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()
的帮助下进行检查,可以用给定的字谜构建单词列表中的哪些单词。然后它返回单词列表中所有可能的单词,可以使用anagram构建。
function preSelectWords($anagram, $wordList){
$tmp = [];
foreach($wordList as $word){
if(!array_diff_once(str_split(strtolower($word)), $anagram))
$tmp[] = $word;
}
return $tmp;
}
现在到主函数decodeAnagram()
。我们将anagram和一个单词列表(我们首先使用preSelectWords()
过滤)作为函数的参数传递。
在函数本身中,我们基本上只是遍历单词,对于每个单词,我们将它从anagram中删除,通过新的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
)
)
(忽略这里的密钥,因为这些是解决方案的标识符)