Php 用递归函数解码字谜不';我们不能给出预期的产出

Php 用递归函数解码字谜不';我们不能给出预期的产出,php,function,recursion,anagram,Php,Function,Recursion,Anagram,所以我试着把我字典里的一个字谜解码成单词。但是我的递归函数并不像我期望的那样 关于代码的想法是消除单词中使用的字母,并将它产生的字符串输出给我 <?php function anagram($string, $wordlist) { if(empty($string)) return; foreach($wordlist as $line) { $line = $org = trim($line); $line =

所以我试着把我字典里的一个字谜解码成单词。但是我的递归函数并不像我期望的那样

关于代码的想法是消除单词中使用的字母,并将它产生的字符串输出给我

<?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);
情况
你有一本字典(文件)和一个包含一个或多个单词的字谜。字谜不包含任何标点符号或原单词的字母大小写

现在,您希望找到所有真正的解决方案,即用完字谜的所有字符,并从字典中将其解码为单词

注意:你可能会找到多种解决方案,你永远不会知道原文是哪一种,单词的顺序是什么,因为多个单词的字符混合在字谜中,你没有标点符号或字母大小写

你的代码 当前代码中的问题正是多个单词混合在一起。如果您现在对它们进行排序,并且希望在字典中搜索它们,您将无法找到它们,因为多个单词的字符是混合的。例如:

anagram  = "oatdgc"  //"cat" + "dog"
wordList = ["cat", "dog"] 


wordListSorted    = ["act", "dgo"]
anagramSorted     = acdgot
                    ↓↓↓
WordListSorted[0] → cat   ✗ no match
WordListSorted[1] → dog   ✗ no match


解决方案 首先,我将从理论上解释我们如何构造所有可能的真实解决方案,然后我将解释代码中的每个部分是如何工作的

理论 首先我们有一个字谜和一本字典。现在我们首先根据字谜来过滤字典,只保留可以由字谜构建的单词

function preSelectWords($anagram, $wordList){
    $tmp = [];
    foreach($wordList as $word){
        if(!array_diff_once(str_split(strtolower($word)), $anagram))
            $tmp[] = $word;
    }

    return $tmp;

}
然后我们检查所有单词,并为每个单词添加一个可能的解决方案,将其从字谜中删除,根据新的字谜过滤字典,然后递归地使用新值调用函数

我们这样做,直到字谜图是空的,我们找到了一个真正的解决方案,我们将其添加到我们的解决方案集合,或者没有剩余的单词,这不是一个可能的解决方案

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);

}
代码 我们的代码中有两个助手函数
array\u diff\u 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;

}
现在转到主函数
decodeangram()
。我们将字谜和单词列表作为参数传递给函数,首先使用
preSelectWords()
对其进行过滤

在函数本身中,我们基本上只是循环遍历单词,对于每个单词,我们将其从字谜中删除,用新的字谜过滤单词列表,并将单词添加到可能的解决方案中,然后递归调用函数

我们这样做,直到字谜图是空的,我们找到了一个真正的解决方案,我们将其添加到解决方案数组中,或者列表中没有单词,并且没有可能的解决方案

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_slice($string,count($line)),$wordlist)
?我的意思是,你只想看看你的字谜是否在你的单词文件中,对吗?@Rizier123,不,字谜可以是多个单词组合成一个句子。@Repox那么你的文本可以包含多个字谜单词,这些单词保存在你的文件中,你想找到所有这些单词吗?@Rizier123,正确。那么这个问题的答案是什么呢?谢谢你的努力,但这不起作用。我只得到排序后的字谜字符串。好吧,我只是把你所做的准确代码放入正确的word文件和字谜,我得到的准确结果是
原始:一个字谜:aaaeeehiikllmprssw
-没有别的了。我知道这个字谜的答案是Willam Shakespeare,而且这两个“单词”都存在于单词本中,我得到了前面提到的结果。@Repox好吧,那么当你已经在字谜中将这两个单词混合在一起并删除了标点符号时,情况会复杂得多,因为你现在可以有多个匹配,因为你把所有的东西都混合在一起了。这就是实际的问题。标点符号和空格不是字谜的一部分。带空格的原始字谜是
我是一个蹩脚的拼写者
,然后可以转换为
威廉·莎士比亚
@Repox,只是为了确保并明确:字谜中没有标点符号,忽略了原始单词的大小写,对吗?