php 使用递归函数解码变位词未给予预期输出

oalqel3c  于 2023-09-29  发布在  PHP
关注(0)|答案(1)|浏览(88)

所以我试着从我的字典文件里把一个变位词解码成单词。但是我的递归函数并没有像我期望的那样运行。
关于代码的想法是消除字母,因为它们用于单词,并向我输出它产生的字符串。

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个单词来自单词列表。

gwo2fgha

gwo2fgha1#

情况

你有一个字典(文件)和一个包含一个或多个单词的变位词。该变位词不包含任何标点符号或原单词的字母大小写。
现在你想找到所有真正的解决方案,你用所有字符的变位和解码成词(S)从字典。

**注意:**有一个机会,你找到多个解决方案,你永远不会知道哪一个原始文本是,在哪个顺序的话,因为多个字的字符是混合在变位,你没有标点符号或情况下的字母。

您的代码

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

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

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

解决方案

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

理论

首先,我们有一个变位词和一本字典。现在,我们首先通过变位词过滤字典,只保留可以由变位词构造的单词。
然后我们遍历所有单词,对于每个单词,我们将其添加到可能的解决方案中,将其从变位词中删除,通过新的变位词过滤字典,并递归地调用具有新值的函数。
我们这样做,直到变位词是空的,我们找到了一个真正的解决方案,我们添加到我们的解决方案集合,或者没有剩余的单词,这不是一个可能的解决方案。

代码

我们的代码中有两个辅助函数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()过滤,作为函数的参数。
在函数本身中,我们基本上只是循环遍历单词,对于每个单词,我们将其从变位词中删除,通过新的变位词过滤单词列表,并将单词添加到可能的解决方案中,然后递归调用函数。
我们这样做,直到变位词是空的,我们找到了一个真正的解决方案,我们添加到我们的解决方案数组,或者没有单词留在列表中,没有可能的解决方案。

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
        )

)

(忽略这里的键,因为它们是解决方案的标识符)

相关问题