用PHP解读单词的最佳方法是什么?

时间:2011-02-15 17:40:35

标签: php algorithm

我有一个单词列表,我想在PHP中使用这个单词列表解读单词。

在我看来,PHP没有内置函数可以做到这一点。那么有人可以建议一个好的算法来做到这一点,或者至少指出我正确的方向吗?

编辑:编辑添加示例

所以基本上,我所说的是我有一个单词列表:

   apple
   banana
   orange

然后,我收到了一堆乱七八糟的信件。

   pplea
   nanaba
   eroang

7 个答案:

答案 0 :(得分:5)

给出一个已知单词的词典:

foreach ($list as $word)
{
  if (count_chars($scrambled_word,1) == count_chars($word,1))
    echo "$word\n";
}

编辑:一个简单的优化是将count_chars($scrambled_word,1))移到循环之外,因为它永远不会改变:

$letters = count_chars($scrambled_word,1)
foreach ($list as $word)
{
  if ($letters == count_chars($word,1))
    echo "$word\n";
}

答案 1 :(得分:3)

警告:我很少使用PHP,因此这只涉及几乎适用于任何语言的通用算法,而不是PHP特有的任何语言。

据推测,你有一个单词,其中字母已被重新排列,你想找到可以从这些字母中产生的单词。

如果这是正确的,一般的想法很简单:获取单词列表的副本,并将每个单词中的字母按字母顺序排序。将每个单词的排序和未排序版本并排放置,并按排序的单词对整个内容进行排序(但保留每个未排序的单词及其排序版本)。您可能希望将重复项折叠在一起,以便(例如)代替{abt:bat}和{abt:tab},您有:{abt:bat,tab}

然后,为了匹配一个混乱的单词,按字母顺序对其字母进行排序。在字典中查找匹配项(因为它已排序,您可以使用二进制搜索)。找到匹配项后,结果就是与该已排序字母组关联的单词(或单词)。使用上面的例子,如果加扰的单词是“tba”,你可以将它排序为“abt”,然后查找“abt”以获得“bat”和“tab”。

编辑:正如@Moron在评论中指出的那样,排序和二元搜索本身并不是关键点。基本要点是将所有等效输入转换为相同的键,然后使用某种快速查找键来查找该键的单词。

对每个单词中的字母进行排序是将等效输入转换为相同键的一种简单方法。对列表进行排序并进行二进制搜索是通过密钥快速查找的一种简单方法。

在这两种情况下,都有很多选择。我完全不确定替代品可能会提高很多性能,但他们当然可以。

例如,您可以使用第二级索引来告诉您以“a”开头的键,以“b”开头的键,依此类推,而不是纯二进制搜索。鉴于字母表开头附近有一些非常常用的字母(例如'e'和'a'),你可能更好地排序单词以便相对不常见的字母( 'q','z'等)朝向键的前面,最常用的字母在最后。这将使基于初始角色的第一次查找成为最大的歧视。

在排序/二元搜索方面,可能有更多的选择,并且可能有更好的参数来支持使用其他东西。散列表通常允许(几乎)恒定时间查找。尝试可以大大减少存储,特别是当许多单词共享共同的前缀时。唯一明显的缺点是任何一个的代码可能更多的工作(虽然PHP的数组类型是基于散列的,所以你可以很好地使用它。)

答案 2 :(得分:1)

可以在O(log p + n)中解读

p = size of dictionary 
n = length of word to be unscrambled

假设一个常数c,在任何单词中加上一些字母的出现次数加1 假设一个常量k,字母表中的字母数 假设一个常量j,可以共享相同散列或字母排序版本的单词数量最多。

O(p)空间的初始化:
1.使用字典D,创建一个字母排序单词L的关联列表,其大小最多为p,因为每个单词都有一个排序版本。
2.将另一列与L相关联,并使用整数的数字散列,其范围可以是[0, c^k-1]。 3.对于L中的每个单词,使用以下函数生成其散列:
hash(word) = 0 if word is empty or (c^i + hash(remaining substring of the word))
其中i是第一个字母从零开始的字母索引。

算法:
1.在O(n)中,确定相关单词的字母排序版本的散列h 2.在O(log p)中,在L中搜索哈希值 3.在O(n)中,列出长度为j的{​​{1}}个相关字词。

答案 3 :(得分:0)

答案 4 :(得分:0)

慢速选项是生成乱码中字母的所有排列,然后通过pspell_check()进行探测。

但是,如果您可以使用原始字典文本文件,那么最好的选择是使用正则表达式来扫描它:

$dict = file_get_contents("words.txt");  // one word per line

$n = strlen($word);
if (preg_match('/^[$word]{$n}$/im', $dict, $match)) {
    print $match[0];
}

我非常确定PCRE在搜索排列方面要比PHP和猜测方法快得多。

答案 5 :(得分:0)

利用PHP的数组函数,因为它们可以为您解决此问题。

$words = array('hello', 'food', 'stuff', 'happy', 'fast');
$scrambled_word = 'oehll';

foreach ($words as $word)
{
    // Same length?
    if (strlen($scrambled_word) === strlen($word))
    {
        // Convert to an array and match
        if( ! array_diff(str_split($word), str_split($scrambled_word)))
        {
            print "Your word is: $word";
        }
    }
}

基本上,你寻找相同长度的东西 - 然后你问PHP看看所有的字母都是一样的。

答案 6 :(得分:0)

如果你有一个非常大的单词列表并希望这个解读操作很快,我会尝试将单词列表放入数据库中。接下来在单词列表中添加一个字段,该字段是单词的ascii值的总和,然后在此ascii总和上添加一个索引。

每当您想要检索可能匹配的列表时,只需在单词表中搜索与加扰字母总和相匹配的ascii总和。请记住,您可能会有一些错误的匹配,因此您必须比较所有匹配的单词,以确保它们只包含您的加扰单词的字母(但结果集应该非常小)。

如果您不想使用数据库,您可以使用文件实现相同的基本想法,只需按照总和值对列表进行排序,以便更快地检索所有匹配项。

示例数据假设全部小写(a = 97,b = 98,c = 99,...)   bat => 311,   cat => 312,......

示例用于计算单词总和的php函数

function asciiSum($word) {
  $characters = str_split(strtolower($word));
  $sum = 0;
  foreach($characters as $character) {
    $sum += ord($character);
  }
  return $sum;
}

更快:向数据库中添加另一个表示字符串长度的字段,然后您可以根据ascii总和和字符串长度搜索单词,这将进一步减少您需要检查的错误匹配数。 / p>