【问题标题】:How do I create subset words for an anagram application (php)?如何为字谜应用程序 (php) 创建子集词?
【发布时间】:2010-11-07 15:19:19
【问题描述】:

我创建了一个字谜创建应用程序,通过在我的数据库中创建一个字谜字段,并使用小写字母顺序存储的字符串。

比如suction变成cinostu,ear变成aer等等。

我现在要做的是从搜索的原始字谜创建子词。

示例:您将如何从搜索“arrest”(即“rest”和“stare”)中提取子集词。

【问题讨论】:

    标签: php string anagram


    【解决方案1】:

    这是我之前使用过的一种方法,它利用了您按字母顺序排列的单词列表。

    1) 获取目标词 (arrest) 并对其进行排序 (aerrst)。

    2) 然后从排序的单词中生成新的字符串,其中每个字母要么被包含,要么被排除。对于 N 个字母的单词,这给出了 2**N 个可能的字符串。 (我不懂 PHP,但如果你愿意,可以给你伪代码或 Python。)

    对于您的目标词,我们有: a, e, r, r, s, t, st, rs, rt, rst, rr, rs, rt, rst, rrs, rrt, rrst, er, er, es, et, est, ers, ert, erst, err, ers, ert, erst, errs, errt, errst, ae, ar, ar, as, at, ast, ars, 艺术, arst, arr, ars, 艺术, arst, arrs, art, arrst, aer, aer, aes, aet, aest, aers, aert, aerst, aerr, aers, aert, aerst, aerrs, aerrt, aerrst

    3) 然后根据您的排序列表检查这些字符串。出现在排序列表中的那些对应于您想要的子集词。

    例如 aerrst 对应于完整的字谜(arrest、rarest、raster...)
    例如 aerst 将在您的排序列表中(凝视,眼泪,...)
    例如 rrs 不会在您的排序列表中

    【讨论】:

      【解决方案2】:

      在原始单词的末尾添加一个空格。空格在字母中间的每次迭代,你都会得到两个单词。然后你可以测试这两个词。如果空格位于迭代模式的开头或结尾,请将其剪掉并测试那个单词。

      【讨论】:

      • 这可能会奏效,但似乎还有很长的路要走。目前我想不出更好的方法,但我感觉有一种更简单的方法……不知何故。好主意。
      • 我正试图弄清楚你的意思。你的意思是逮捕会以凝视、耳朵或休息的形式出现。或者一个词会与另一个词结合,总是等于原始字谜中的字符数。
      • 所以在你开始之前“逮捕”变成了“逮捕”。注意最后的新空间。一些迭代将返回“r staer”。这两个词都没有意义。下一次迭代将返回“r stare”。啊哈! “盯”!最终,一个人会返回“ar rest”。另一个将返回“star re”。等等。
      【解决方案3】:

      我还没有有意义地考虑这个,抱歉(工作要做!),但是不管你最终生成了单词,不要忘记这会像妈妈一样缓存,所以不要重新生成每次有人搜索时,这些都是即时的。

      CS.

      【讨论】:

        【解决方案4】:

        这种方法与您的方法略有不同,但我相信它很容易以编程方式实现。我不确定它是否具有最佳性能,但我会把它留给你:-)

        首先,您需要一本包含您希望能够匹配的所有合法单词的字典。

        在您的数据库中创建一个“字典”或“单词”表,第一列存储实际单词,第二列存储单词全部转换为大写或小写以便于比较,然后每个整数列字母 AZ 中的字母。

        将您的字典文件导入此表,并以编程方式计算字母表中每个字母出现在该单词中的次数,并将该数字存储在该字母的列中。

        例句:bookkeeper

        在单词列中存储单词“bookkeeper”,在“b”、“p”和“r”列中存储 1,在“o”和“k”列中存储 2,在“e”中存储 3列。

        一旦您导入了包含字母计数的整个词典,您就可以使用以下方法相当轻松地确定给定单词中所有可能的子单词:

        • 数一数字符串中的字母。
        • 编写一个 SQL 查询,返回字典表中的所有单词,这些单词不使用在给定单词中找不到的字母,或者包含的任何特定字母多于单词中存在的字母。

        您可以通过创建一个包含 26 个位置的内存数组来表示字母表来实现这一点

        示例词:车辆

        SELECT Word FROM Dictionary WHERE NOT (
          (a >= 1) OR (b >= 1) OR (c >= 2) ... OR (z >= 1)
        )
        

        因此,您的字典中包含“a”或“z”的任何单词都将被排除,因为查询将过滤掉“a”或“z”计数至少为 1 的任何单词,并且任何使用多个“c”的词都会被过滤掉。

        您可以通过使用由 26 个整数组成的数组(全部从 1 开始)以编程方式轻松生成所有“OR”条件,然后遍历您的单词,将 1 加到您找到的每个字母的相应数组值中。

        更新 - 最终计数示例代码

        请原谅我下面的代码示例 - 它将在 ASP (VBScript) 中 - 但您应该能够掌握并翻译成 PHP,或者如果没有,请一位好心的人为您执行此操作。

        Const AsciiCodeLowerCaseA = 97
        InputWord = "Carrots"
        LowerCaseInputWord = LCase(InputWord)
        
        Dim LetterCount(26)
        
        for i = 1 to 26
          LetterCount(i) = 1
        next
        
        for j = 1 to Len(InputWord)
          CurrentLetter = Mid(InputWord, j, 1)
          AsciiCode = Chr(CurrentLetter)
          AlphabetPos = AsciiCode - AsciiCodeLowerCaseA + 1
          LetterCount(AlphabetPos) = LetterCount(AlphabetPos) + 1
        next
        

        通过将单词的每个字母转换为其 ASCII 值,然后减去小写“a”的 ascii 代码并加 1,您可以得到该字母在字母表中的位置,从 1 到 26。现在您将 1 加到数组中的那个位置。

        这似乎违反直觉,但将数组中的所有字母初始化为 1。当您构建 SQL 语句时,您将消除所有字母计数高于输入单词的单词 - 因此,如果原始单词中没有出现某个字母,您将过滤掉包含一个或多个该字母的单词。如果该字母出现一次,则过滤掉包含两个或更多该字母的单词,依此类推。

        【讨论】:

        • 我实际上已经准备好在我的数据库中拥有所有的 a-z。我是按照这些思路工作的。这只是我正在努力解决的问题。这可能是我一直在寻找的答案。我会试一试,让你知道我是怎么做的。谢谢博克。
        • 所以我创建了一个 26 键数组: $alpha_array = array("a" => 0, "b" => 0, "c" => 0) 等等。我想要做的是遍历我的爆炸输入字符串..即用户输入的字符串,如果存在字符,我想编辑 $alpha_array 并将一个添加到该实例中的数组中。然后我可以在此之后构造一个 SQL 语句。有什么想法吗?
        • 我将修改我的答案以尝试解释这一点。
        【解决方案5】:

        嘿博克。一直在尝试将您的代码改编成 PHP,我有以下内容:

        $LetterCount = array("a" => 1, "b" => 1, "c" => 1, "d" => 1, "e" => 0, "f" => 1, "g" => 1, "h" => 1, "i" => 1, "j" => 1, "k" => 1, "l" => 1, "m" => 1, " n” => 1, “o” => 1, “p” => 1, “q” => 1, “r” => 1, “s” => 1, “t” => 1, “u " => 1, "v" => 1, "w" => 1, "x" => 1, "y" => 1, "z" => 1);

        $AsciiCodeLowerCaseA = 97;
        
        for ($j = 1; $j < strlen($string); $j++) {
          $CurrentLetter = $string[$j];
          $AsciiCode = ord($CurrentLetter);
          $AlphabetPos = $AsciiCode - $AsciiCodeLowerCaseA + 1;
              $LetterCount[$AlphabetPos] = $LetterCount[$AlphabetPos] + 1;
        }
        

        我硬编码了数组声明位以节省时间。

        无论如何,它似乎没有工作并给了我这个错误:注意:未定义的偏移量:1

        这是我遇到的错误的屏幕截图,我还为循环中的每个 var 或数组添加了回显,看看你是否能理解发生了什么。

        http://i42.tinypic.com/11ryz4g.png

        我认为它没有正确识别数组中的 aplhabet 字母,因此错误地将数字添加到数组的末尾。

        让我知道你认为我应该怎么做。

        【讨论】:

          【解决方案6】:

          安迪,

          我认为您需要将 ASCII 代码转换回字符 - 您正在使用字母索引数组,但您正在使用 ASCII 值访问它。

          这是您的代码,稍作修改:

          $LetterCount = array("a" => 1, "b" => 1, "c" => 1, "d" => 1, "e" => 0, "f" => 1, "g" => 1, "h" => 1, "i" => 1, "j" => 1, "k" => 1, "l" => 1, "m" => 1, " n” => 1, “o” => 1, “p” => 1, “q” => 1, “r” => 1, “s” => 1, “t” => 1, “u " => 1, "v" => 1, "w" => 1, "x" => 1, "y" => 1, "z" => 1);

          $AsciiCodeLowerCaseA = 97;
          
          for ($j = **0**; $j < strlen($string); $j++) {
            $CurrentLetter = $string[$j];
            $AsciiCode = ord($CurrentLetter);
            $AlphabetPos = **chr($AsciiCode - $AsciiCodeLowerCaseA + 1);**
            $LetterCount[$AlphabetPos] = $LetterCount[$AlphabetPos] + 1;
          }
          

          另外我刚刚注意到您正在从 1 开始索引字符串中的字符,但数组是零索引的。

          我认为这也可能更简单(除非我遗漏了什么)

          for($j = 0; $j < strlen($string); $j++) {
          $LetterCount[$string[$j]]++;
          }
          

          【讨论】:

          • 谢谢罗伯。它现在正在工作......无论查询的字母数是多少,都需要 20 秒来执行页面。可接受的速度,现在将寻求改进。再次感谢大家!
          猜你喜欢
          • 2016-02-01
          • 2013-08-07
          • 2015-07-26
          • 2016-05-21
          • 2011-10-29
          • 2012-07-22
          • 1970-01-01
          • 1970-01-01
          • 2013-02-11
          相关资源
          最近更新 更多