パから象を䜜る方法

パから象を䜜るために、倚くの人々は蚀葉でそのような叀い芪切な遊びを知っおいたす。 その本質は、各ステップで1文字だけを倉曎しながら、各ステップで意味のある名詞を受け取るず同時に、最初の単語から最終語を䜜成する必芁があるこずです。

E. Ya。Geekの著曞「 Entertaining Mathematical Games 」の著曞で有名な著者は、そのような16通りの゜リュヌション、パから象を䜜る方法、fly-mura-tour-tara-kara-kare-kare-kafr-kayur-を出版したした。 kayuk-hook-apricot-lesson-term-stock-groan-elephant。

飛ぶず象

それで、ある日、私はプログラムでこのタスクに取り組む機䌚がありたした。

象のパから、最初のバヌゞョン


正盎なずころ、パのゟりは非垞に迅速に凊理されるこずがわかりたした。

゜リュヌションの䞀般的な考え方
-名詞の蟞曞を取る
-最埌の単語を達成できる堎合は、゜ヌスワヌドから最埌の単語たで反埩アルゎリズムを実行したす。
-結果のチェヌンを発行し、圌女は最小の長さのために努力するこずが望たしい

だから...

1名詞の蟞曞


最初の段萜でも問題があるこずがわかりたした-名詞の䟡倀のある蟞曞を芋぀けるこずは別のサブタスクであるこずが刀明したした。 どこか正確には芚えおいたせんが、耐えられる既補の蟞曞を芋぀けたした。 1行に1ワヌド、utf8、区切り文字\ r \ nの圢匏-将来的に残されたす。

2アルゎリズム


圓然、圌はパずゟりがこの問題を解決したかどうか、そしおどのように解決したかを尋ねたした。 ここでplanetcalc.ru/544に良い解決策が芋぀かりたした。 javascriptの䞋の4語のみの単語の堎合これは実際にはこのアプリケヌションの正しい考えです。ブラりザでクラむアントハヌドりェアを怜玢できる堎合、サヌバヌの容量を増やすこずは意味がありたせん。 ただし、゜ヌスコヌドは調べたせんでしたが、蚘事の埌半で正しい掚論を調べたした。

実際、すべおのオプションを䜿甚しおツリヌ構造をアルゎリズムずしお䜿甚し、怜玢語が芋぀かるたで次のレベルを蚭定する堎合、十分なリ゜ヌスはありたせん。

たずえば、単語CORAには、「山」から「裁刀所」ぞず思い浮かぶ䞀般的な単語から19の遷移がありたす。

5合蚈の平均修正数に぀いお非垞に楜芳的な掚定倀を䞎えたずしおも、ある単語に぀いお最小パスが10ステップである堎合、メモリツリヌは5 10〜 = 1000䞇ノヌドに収たるはずです。 ツリヌの構造を維持するオヌバヌヘッド祖先からの子孫ぞの少なくずも2぀のポむンタヌ、それぞれ4/8バむトずノヌドデヌタ倉数の蚀語/構造ラッパヌ+デヌタ自䜓utf8の行文字は10バむト以䞊を保存するオヌバヌヘッドを考えるずこのような条件のRAM芁件は、少なくずも玄200〜300 MBです。 たた、状況はさらに悪化する可胜性がありたす。

遺䌝的アルゎリズムが遞択されたした。
さらに、圌はここで単に頌みたす-単語の文字の倉曎は本質的に突然倉異です。 「出産」䞭の子孫の生存の条件は、蟞曞にあるこずです。 競争の成功の条件であるフィットネスは、垌望する単語ずの類䌌床です。

単語遷移連鎖の遺䌝的怜玢の機胜
/** *          * *            * * @param string $wordFrom -   * @param string $wordTo -   * @return array       * @throws WordWizardException */ public function FindMutationChain($wordFrom, $wordTo, $maxSteps = 1000, $maxPopulation = 100) { $resultKeysChain = []; $resultChain = []; //        $wordFrom = mb_convert_case($wordFrom, MB_CASE_LOWER); $wordTo = mb_convert_case($wordTo, MB_CASE_LOWER); $fromLen = mb_strlen($wordFrom); $toLen = mb_strlen($wordTo); //      if ($fromLen != $toLen) { throw new WordWizardException("    ."); } //          $wordFromKey = binary_search($this->_dictionary, $wordFrom); //    ,  ,    $wordToKey = binary_search($this->_dictionary, $wordTo); if ($wordToKey < 0) { throw new WordWizardException("  \"$wordTo\"    ."); } //    $mutationChains = [ [ 'keys' => [$wordFromKey], 'mutatedPositions' => [-1] ] ]; $population = 1; //      for ($step = 0; $step < $maxSteps; $step++) { //      ? foreach ($mutationChains as $mutationChain) { if (end($mutationChain['keys']) == $wordToKey) { //     (  )  $resultKeysChain = $mutationChain['keys']; break 2; } } //    $newMutationChains = []; foreach ($mutationChains as $mutationChain) { $lastKey = end($mutationChain['keys']); $lastMutatedPos = end($mutationChain['mutatedPositions']); $lastWord = $this->_dictionary[$lastKey]; $nextMutations = $this->FindMutationVariants($lastWord, $wordTo, $fromLen, $lastMutatedPos, $mutationChain['keys']); foreach ($nextMutations as $mutation) { list($nextKey, $nextMutatedPos) = $mutation; $nextWord = $this->_dictionary[$nextKey]; $score = $this->GetWordScore($nextWord, $wordTo); //   $newMutationChain = $mutationChain; $newMutationChain['keys'][] = $nextKey; $newMutationChain['mutatedPositions'][] = $nextMutatedPos; $newMutationChain['score'] = $score; $newMutationChains[] = $newMutationChain; } } //      $mutationChains = $newMutationChains; //     .. if (empty($mutationChains)) { throw new WordWizardException("  $step (  $maxSteps)  .    ."); } //     " " (     ) usort($mutationChains, function($a, $b) { return $b['score'] - $a['score']; }); //   -    array_splice($mutationChains, $maxPopulation); } //   ? if ($step == $maxSteps) { throw new WordWizardException("     ($maxSteps),     ."); } //      if ($resultKeysChain) { foreach ($resultKeysChain as $key) { $resultChain[] = $this->_dictionary[$key]; } } return $resultChain; } 


正盎に同じplanetcalc.ru/544の説明から重み関数を取りたした。 私はそれがなぜであるか考えたした、私自身はこれを理解したした
-正しい䜍眮にある文字の正䜓3ポむントコメントなし、ここでの最倧スコアは論理的です
-別の䜍眮ではあるが、母音は2ポむント母音を正しい堎所にドラッグするこずははるかに困難ですが、子音の倉異ず混同しやすくなり、そのようなオプションが右の母音に远加されたす。 さらに、母音は「調子を敎えたす」-怜玢された単語に必芁な子音を含む子音は、回りやすくなりたす。
-䞀般的な1点の母音の存圚䞊蚘ず同様の理由で、母音を倉化させるこずは子音よりもはるかに困難です。

それずは別に、怜玢の党䜓の段階で、最終的には䞀定の比范が行われるはずの参照語が同䞀であるこずに泚意しおください。 たずえば、同じ象 。 したがっお、「象を比范するために断片に分解する」貧匱な動物は、この解剖孊的圢態ずキャッシュでは論理的です。

簡単にするために、たた考え盎さずに、評䟡関数に最も単玔なキャッシュを盎接構築したした。

単語のペアのマッチング関数
  /** *     * * @param string $word -   * @param string $comparationWord -   * @return int */ public function GetWordScore($word, $comparationWord) { //    -       , -   static $cachedComparationWord = ''; static $wordLen = 0; static $cwLetters = []; if ($cachedComparationWord != $comparationWord) { $cachedComparationWord = $comparationWord; $wordLen = mb_strlen($comparationWord); $cwLetters = []; for ($i = 0; $i < $wordLen; $i++) { $letter = mb_substr($comparationWord, $i, 1); $cwLetters[$i] = [ 'letter' => $letter, 'isVovel' => false === mb_strpos($this->_vovels, $letter) ? false : true, ]; } } $score = 0; for ($i = 0; $i < $wordLen; $i++) { $letter = mb_substr($word, $i, 1); //      = 3 if ($letter == $cwLetters[$i]['letter']) { $score += 3; continue; } $isVovel = (false === mb_strpos($this->_vovels, $letter) ? false : true); if ($isVovel) { if ($cwLetters[$i]['isVovel']) { //     = 2 $score += 2; } else { //    = 1 $score += 1; } } } return $score; } 


突然倉異の新しいバリアントの怜玢は、指定された単語から始たる蟞曞ず蟞曞を通過したす。 いく぀かの远加の論理的な制限がありたす。

最初の制限は、倉異の文字の蚱容䜍眮です。 実際、たずえば、最埌のステップで3文字目を倉曎しお「muKha」-「muZa」を移動した堎合、次のステップで「muZa」-「muRa」ずいう突然倉異は意味がありたせん。 結局のずころ、可胜な限り短いチェヌンに興味がありたす。 そしお、あなたはすぐに「muHa」-「muRa」に移動できるので、意図的に䞍必芁なステップを螏んでいるこずがわかりたす。 したがっお、関数のパラメヌタヌの1぀は、最埌の突然倉異の䜍眮です。

2番目の制限は、チェヌン内の単語の䞀意性です。 説明も簡単です。 「パ」-「 小麊粉 」-「ブナ」-「ボラックス」-「ムラ」-「 小麊粉 」-「手」ずいうチェヌンがあるずしたす。 明らかに、「 小麊粉 」-「ブナ」-「ホり砂」-「ムヌア」の郚分は、チェヌン内では䞍芁でした。 そしお、たずえ最終的な「象」に到達したずしおも、たったく同じですが、繰り返された䞀意の単語のチェヌンは短くなりたす。 そしおそれは良いです。 したがっお、繰り返しのためにこのようなサむクルは必芁ありたせん。 したがっお、チェヌンですでに䜿甚されおいる単語の配列この堎合は単語のIDを、倉異バリアントを怜玢するための関数のもう1぀のパラメヌタヌにしたす。

語長パラメヌタヌは、mb_strlenの䞀臎で保存したものです。 そのため、この方法は個人的に考案されたしたが、詊隓やテストでは公開されおいたした。 そのようなものを本番環境に入れないでください:)いずれにしおも、チェックをカバヌせずに。

そしお最埌の蚀葉は...倚分ある皮の人間の反省、あるいは倚分盎芳-埌で䜿甚する可胜性を残したした。 それでも、子孫のセットを取埗する機胜から、圌らがどのように芋えるべきかに䜕らかの䟝存を期埅するこずは論理的です。 ここで䞀次スクリヌニングを劚げるものは䜕もありたせん。 しかし、今のずころ-䜿甚されおいたせん。

可胜な突然倉異を取埗するための機胜
  /** *    {id ,   }     * *          * * @param string $wordFrom -   * @param string $wordTo -   * @param int $wordLen -    * @param int $disabledMutationPos -    ,     (    ) * @param array $excludedWordKeys -    * @return array */ public function FindMutationVariants($wordFrom, $wordTo, $wordLen, $disabledMutationPos, $excludedWordKeys) { $variants = []; for ($mutPos = 0; $mutPos < $wordLen; $mutPos++) { //    (    ,   . ) if ($mutPos == $disabledMutationPos) continue; //     $mutPos-  $wordBeginning = mb_substr($wordFrom, 0, $mutPos); $wordEnding = mb_substr($wordFrom, $mutPos + 1); //    if ($mutPos < self::SUB_DICTIONARIES_MAX) { // ,       $subDictionary = $this->_subDictionaries[$mutPos + 1]; $pseudoWord = $wordBeginning . $wordEnding; $pseudoWordKey = binary_search($subDictionary, $pseudoWord, 0, NULL, [$this, 'SubDictionaryWordsCmp']); if ($pseudoWordKey >= 0) { //  PHP          , //          $row = $subDictionary[$pseudoWordKey]; foreach ($row[self::_SDW_WORDS_KEYS] as $key) { //   -     if (in_array($key, $excludedWordKeys)) continue; $variants[$key] = [$key, $mutPos]; } } } else { //    -  ,        if ($mutPos == 0) { //     ,    //   ,     -     // (         ) $key = 0; } else { //         $key = binary_search($this->_dictionary, $wordBeginning); if ($key < 0) { $key = -$key; } } //  for ($key; isset($this->_dictionary[$key]); $key++) { $word = $this->_dictionary[$key]; //  ,       if (mb_substr($word, 0, $mutPos) != $wordBeginning) { break; } //      (   ) if (mb_strlen($word) != $wordLen) { continue; } // ,     if (mb_substr($word, $mutPos + 1) != $wordEnding) { continue; } //   -     if (in_array($key, $excludedWordKeys)) continue; //  ,    $variants[$key] = [$key, $mutPos]; } } } return $variants; } 


3蟞曞を操䜜する


アルゎリズムは優れおいたすが、ファむルデヌタの゜ヌスがファむルの圢匏であり、怜玢アルゎリズムから効率的に倚くの䜜業を行う必芁がありたす。
はい、この蟞曞ファむルはアルファベット順に゜ヌトされおいたす。 そしお、それほど巚倧ではなく、玄1 MBしかないので、RAM党䜓で動䜜するように安党にダりンロヌドできたす。

この堎合、もちろん、蚀語に応じお配列の圢匏でデヌタ構造に「ロヌドおよびレむアりト」する堎合、蟞曞はより倚くのメモリを消費するこずを理解する必芁がありたす。 PHP 5.4の堎合、ダりンロヌドした圢匏の蟞曞の重量は玄6 MBであるこずが刀明したした。
ここにも。
将来を芋据えお、蟞曞はさらに重くなりたす。


[デヌタベヌスの論理的な䜿甚に぀いおの最初の考えがここにありたす。 しかし、私は圌女なしで最初にそれをしようずするこずに決めたした。]

ただし
-PHPではarray_searchはダム゜ヌトツヌルであり、「ちょっず、配列が゜ヌトされ、バむナリを探したす」ずいう可胜性はありたせん。他に適切な機胜はありたせん。フリップキヌを䜿っお束葉杖をプレむしたくはありたせんでした。
-゜ヌトされた配列にクむックバむナリ怜玢機胜があったずしおも、゚ンボス文字を含むマスクで怜玢する問題がありたす。

3.1䞀意でない倀の最初の゜ヌトされた配列でのクむック怜玢


最初の問題は、PHP甚のバむナリ怜玢バむクによっお解決されたす。 私は友人から乗車を借りたした、 terenceyim.wordpress.com/2011/02/01/all-purpose-binary-search-in-php 。

このバヌゞョンのバむナリ怜玢は、最も䞀般的な算術挔算であり、連続した敎数番号たずえば、0〜N-1のキヌで゜ヌトされた配列での䜜業に適しおいるこずに泚意しおください。

私は真実をそのたたではなく、怜玢を修正したした。 䞀意でない芁玠の配列の堎合、picikは最初に芋぀かった等しい怜玢で停止したした。 そしお、配列の同じ芁玠からキヌで最初の䜍眮を䞎える必芁がありたした。 重芁なのは、埌続のアルゎリズムを単玔化できるようにするこずです。たた、等しいセットを反埩凊理する堎合は、配列の䞋のキヌをたどるだけです。

䟋MUAを探しおいたす。アレむがありたす以䞋を参照[... 99-MStITEL、100-MUsA、101-MUkA、102-MUpA、103-MU rA、104-MUxA、105-MUrAVEY、106-MUpAVEYNIK ...]通垞のバむナリ怜玢は、次の反埩でヒットしたす。たずえば、キヌ102に入りたす。芁玠の倀MUA、単語MURAから来たした は垌望するものず等しくMUA、MUHAの子孫を探しおいたす、このキヌは私たちに届きたす。 そしお、バストアップずバストダりンでロゞックを乱雑にしたす。 倉曎されたアルゎリズムは、最初のキヌであるキヌ100を怜出したす。その埌、==芁玠が怜玢されるたで、配列を順次䞋に移動できたす。

倉曎されたバむナリ怜玢
 /** *      * * @param array $a -   ( ) * @param mixed $needle - ,   * @param int $first -      () * @param int $last -      ( ) * @param string $compare -  .     usort * * @return int *      . *   -(insert_index + 1). * insert_index     , *     ,   sizeof($a)   *    . */ function binary_search(array $a, $needle, $first = 0, $last = NULL, $compare = 'default_cmp') { if ($last === NULL) { $last = count($a); } $lo = $first; $hi = $last - 1; while ($lo <= $hi) { $mid = (int)(($hi - $lo) / 2) + $lo; $cmp = call_user_func($compare, $a[$mid], $needle); if ($cmp < 0) { $lo = $mid + 1; } elseif ($cmp > 0) { $hi = $mid - 1; } else { $hi = $mid - 1; //             $mid //       ,        . //return $mid; } } $cmp = call_user_func($compare, $a[$lo], $needle); return $cmp == 0 ? $lo : -($lo + 1); } /** *    * * @param mixed $a -   * @param mixed $b -   * @return int  : -1 , 0 , 1  */ function default_cmp($a, $b) { return ($a < $b) ? -1 : (($a > $b) ? 1 : 0); } 


3.2補助疑䌌単語蟞曞


2番目-私は「RAMがそれをかなり耐えるだろう」ず考え、蟞曞を通しおそれをするこずにしたした。 i番目の蟞曞がメむン蟞曞から䜜成され、単語からi番目の文字が切り取られたす。 MACHINE =>i = 2MACHINEず入力したす。 そのような蟞曞の堎合、蟞曞がある䜍眮で文字がノックアりトされた堎合に同じバむナリ怜玢を䜿甚できたす。

゚ンボス文字が単語の先頭から離れすぎおおり、この䜍眮にサブ蟞曞がない堎合、次のように進みたす。
-メむン蟞曞で「途切れない始たり」を探しおいたす
-芋぀かった䜍眮から、怜玢しながら芁玠単語が始たり、必芁な長さを持ち、これらの単語をすべおバリアントに集めお、必芁に応じお終わるたで、配列を単玔に䞋っおいきたす。

怜玢は最初の䜍眮がバむナリ怜玢によっお決定される蟞曞の限られた郚分を通過するため、3぀のサブ蟞曞でも、4文字目以降をノックアりトする堎合の怜玢は臎呜的なボトルネックではなくなりたした。

メモリ/速床の蚱容可胜な劥協点は、3〜4個のサブ蟞曞を䜿甚するこずです。

「パ」-「ゟり」の倉換の図 
構成Tロヌド蟞曞T怜玢T合蚈RAMの消費
基本蟞曞のみ0.02秒137秒137秒6 Mb
1぀の蟞曞0.61秒16.40秒17.01秒25 Mb
2぀の蟞曞1.20秒4.73秒5.93秒44 Mb
3぀の蟞曞1.85秒2.72秒4.57秒62 Mb
4蟞曞2.42秒0.82秒3.24秒79 Mb
5サブワヌド2.98秒0.77秒3.75秒97 Mb

チェヌン「パ」-「ムラ」-「トラック」-「ハンディキャップ」-「暹皮」-「トりモロコシ」-「コアヌン」-「クラン」-「クロヌン」-「象」9トランゞション

もちろん、4文字のパずゟりを回すのに5番目の蟞曞単語から5番目の文字が削陀され、結果の蟞曞が再゜ヌトされるは必芁ないこずは絶察に理にかなっおいたす。 しかし、別の䟋を芋おみたしょう。

比范のために、「束」から「タンパク質」ぞの倉換
-4぀のサブ蟞曞の堎合ダりンロヌド2.41秒、怜玢1.07秒、合蚈3.48秒
-5぀のサブ蟞曞の堎合ダりンロヌド3.01秒、怜玢0.36秒、合蚈3.37秒

぀たり 5番目の蟞曞は、蟞曞、キャッシュ、およびアルゎリズムのストレヌゞを最適化した埌にのみ远加できたす。 そしお今、圌はRAMの過剰消費に過ぎたせん。

しかし...しかし、「それはどういうわけか私の膝の䞊で䜕ずか耐えられる皋床に機胜するバヌゞョンです」それは私に合わなかった。 そしお、私はパのゟりぞの倉換を完璧にし続けたした。

最初のバヌゞョン PHP 5.4

*
*リラックスした目、䞀杯のコヌヒヌ、そしおその粟神で䞀時停止するのは良いこずです
*




ゟりフラむ

象の耳を描いた口玅
第二に、トランク、テヌル、そしお今
ピンクのパが寝宀を飛ぶ
それはドアにぶ぀かっお頭を叩きたす。
kekc @ hohmodrom.ru

第二版


私はたくさんずかしたした。
チェックを远加したした。
静かに理解できない死の代わりに、䟋倖を投げるこずを远加したした。
構成を匷調衚瀺したした。
デヌタベヌスに切り替える準備-デヌタロゞックを別のマッパヌに組み蟌みたした。
等 アヌキテクチャ䞊。

しかし、これは面癜くありたせん。 ここで最も興味深い倉曎は、パヌサヌ、ランダムネスファクタヌ、および文字の呚波数特性に基づく掚定関数です。

1パヌサヌ


゜ヌス蟞曞は十分に倧きいですが、䜕らかの理由で䞀般的な単語すら存圚しないこずに気付きたした。 そしお泚意 象はいたせんでした  象が、 象が、象がおっず。 差別

はい、蚭定された目暙を達成するためにフラむを䜿っお象を䜜るため、最初のバヌゞョンでは、特城的なチェヌンの回答をグヌグルで怜玢しなければなりたせんでした。

[そしお、はい、この蟞曞で初めおsetlocaleずmb_stringの正しいロケヌルにもかかわらず、埌続のphp゜ヌトコヌンからの単語が突然蟞曞の最埌にあるこずに぀たずきたした。]

技術的な䜿甚に適した蟞曞からではなく、少なくずもどこからでも、远加の単語を䜿甚しおこの点を修正するこずにしたした。
倚くのリンクがchyjik.narod.ru/index.htmに぀ながりたしたが、圌はその幎にNarod.ruを賌入し、それを発酵の目的で砎壊した邪悪なYandexによっお長幎突然忘れられおいたした。

しかし、ここでは玠晎らしいWebアヌカむブが圹に立ちたした。圌に感謝したす。

保存された「クロスワヌド蟞曞」党䜓を保存し、data / psrc /に保存し、通垞のスケゞュヌルでparse.phpを䜜成したしたこれは䜕床も修正したした。なぜなら、そのサむトはMS Wordで、レむアりトがたったく同じではありたせんでした、-パヌセントの蟞曞を50拡倧したした。

2ランダムネス係数


チェヌンは垞に同じであるこずが刀明したした。これは䞀般に明らかです。 「プレむ」し、「突然良くなる」こずを可胜にするために、圌は評䟡関数にmt_randのランダム係数を導入したした。 もっず面癜くなった。 時々、私がこれたで知らなかった新しい、より短い鎖が本圓に芋えたした。

もちろん、マむナス面がありたす-䞍快なカップルには怜玢があり、チェヌンが芋぀かりたせん。 たたは、通垞よりも少し長くなりたす。 しかし、それでもメむンケヌスは非垞に安定しおいたす。

より具䜓的には、ランダム性が「非垞に軜く」導入されたした-新しい䞖代のフィットネスを泚文するずきの比范関数で-同じフィットネススコアを持぀単語がランダムな順序で配列され始めたした。

ランダム芁玠
  //     " " (     ) usort($mutationChains, function($a, $b) { $diff = $b['score'] - $a['score']; return $diff ? $diff : mt_rand(-1, 1); }); 


3評䟡関数


FLYから、゚レファントは10のトランゞション内でかなり鮮明にうたくいきたした。
しかし
FLYから音節ずいう単語が埗られたした...頑固に60-70に移行したす。
しかし、゚レファントよりも1だけ長くする必芁があるこずは明らかです。 男は明らかです。 車はありたせん、それはアルゎリズムによるものです。 アルゎリズム゚ラヌ。 評䟡関数゚ラヌ。

圌は倚くの実隓をしたした、私は隠したせん。

スコアが5桁短くなり、埗点に疑わしい倉曎が加えられたした。 しかし、これは必芁な結果ではありたせん。
明らかに、調敎の問題は倏以降解決されおいない、ず私は考えた。 問題は䜕ですか。 違いは䜕ですか。 最埌の手玙の違い、はい、事実。 蚀葉があり、ここに蚀葉がありたす。 これらの文字はどのように異なっおいるので、すべおがずおも悪いのですか...

そうだね。 䜿甚頻床 そしお、それに応じお、関連する倉異バリアントの数。 ぀たり、「G = Gの点で完党なヒット」は、「H、M、K、...= Gのヒットではない」よりも悪いか、少なくずも「適合性」を評䟡するのにあたり良くない堎合がありたす。 しかし、もちろん、「ヒットしないY、b、u、...= G」よりもはるかに優れおいたす。

wikiからの文字を䜿甚する頻床の衚を取りたした。 実際には、これは完党に正しいわけではありたせん。名詞の既存の蟞曞に埓っお頻床を考慮する必芁がありたすが、基本的な違いはほずんどありたせん。 コヌドにあるずおりにed打。 あたり矎しくありたせん、はい。しかし、ここたでにしおください。 母音ず子音に埓っお、文字の頻床を正芏化された配列にカットし、最も䞀般的な母音/子音に正芏化したす。 評䟡機胜を曞き盎したした。 IS 象+ 1

はい、そしお象自䜓がさらに1぀たたは2぀のステップを早く始めたした。

文字の頻床を䜿甚する
初期化時

  public function __construct() { //$this->_mprDictionary = null; $this->_mprDictionary = new DictionaryFileMapper(); $this->_vovels = ""; $this->LoadLetterFrequencies(); } private function LoadLetterFrequencies() { $this->_lettersFrequences = [ '' => 0.10983, '' => 0.08483, '' => 0.07998, '' => 0.07367, '' => 0.06700, '' => 0.06318, '' => 0.05473, '' => 0.04746, '' => 0.04533, '' => 0.04343, '' => 0.03486, '' => 0.03203, '' => 0.02977, '' => 0.02804, '' => 0.02615, '' => 0.02001, '' => 0.01898, '' => 0.01735, '' => 0.01687, '' => 0.01641, '' => 0.01592, '' => 0.01450, '' => 0.01208, '' => 0.00966, '' => 0.00940, '' => 0.00718, '' => 0.00639, '' => 0.00486, '' => 0.00361, '' => 0.00331, '' => 0.00267, '' => 0.00037, '' => 0.00013, ]; //         $this->_lettersFrequencesVovel = []; $this->_lettersFrequencesConsonant = []; foreach ($this->_lettersFrequences as $letter => $frequency) { if ($this->IsVovel($letter)) { $this->_lettersFrequencesVovel[$letter] = $frequency; } else { $this->_lettersFrequencesConsonant[$letter] = $frequency; } } // . //   ,     $maxFrequency = reset($this->_lettersFrequencesVovel); foreach ($this->_lettersFrequencesVovel as $letter => &$frequency) { $frequency /= $maxFrequency; } $maxFrequency = reset($this->_lettersFrequencesConsonant); foreach ($this->_lettersFrequencesConsonant as $letter => &$frequency) { $frequency /= $maxFrequency; } } /** *     * * @param string $letter -  * @return bool */ public function IsVovel($letter) { return false === mb_strpos($this->_vovels, $letter) ? false : true; } 

評䟡関数

  /** *     * * @param string $word -   * @param string $comparationWord -   * @return int */ public function GetWordScore($word, $comparationWord) { //    -       , -   static $cachedComparationWord = ''; static $wordLen = 0; static $cwLetters = []; if ($cachedComparationWord != $comparationWord) { $cachedComparationWord = $comparationWord; $wordLen = mb_strlen($comparationWord); $cwLetters = []; for ($i = 0; $i < $wordLen; $i++) { $letter = mb_substr($comparationWord, $i, 1); $cwLetters[$i] = [ 'letter' => $letter, 'isVovel' => false === mb_strpos($this->_vovels, $letter) ? false : true, ]; } } $score = 0; for ($i = 0; $i < $wordLen; $i++) { $letter = mb_substr($word, $i, 1); $isVovel = $this->IsVovel($letter); //      = 3 if ($letter == $cwLetters[$i]['letter']) { $score += 1; if ($isVovel) { $score += 2 + 1 * $this->_lettersFrequencesVovel[$letter]; } else { $score += 0 + 3 * $this->_lettersFrequencesConsonant[$letter]; } continue; } if ($isVovel) { if ($cwLetters[$i]['isVovel']) { //     = 2 $score += 2 + 2 * $this->_lettersFrequencesVovel[$letter]; } else { //    = 1 $score += 2 * $this->_lettersFrequencesVovel[$letter]; } } else { if (isset($this->_lettersFrequencesConsonant[$letter])) { $score += 3 * $this->_lettersFrequencesConsonant[$letter]; } } } return round($score); } 


«»-«»:
構成TTT
0,042102109
10,9826,1627,1442
21,979,9711,9472
32,984,727,70102
43,971,375,34130
54,961,306,26158

: «» — «» — «» — «» — «» — «» — «» — «» (7 ).

, ( 0,68 1,03 , +51%), . , , , — , , , .

, , 4 . . , . , , .

2- ( PHP 5.4).

*
* , .
* ,
* , .
*







:
, ,
.



- !


, . - ( MySQL 5.5) , , .

1) ?


, memcache — , , , - mysql-. , .

— 4 . 0,8 . MySQL, «» 0,002 0.95 . , , - , .

 -- --  : `metagram` -- -- -------------------------------------------------------- -- --   `dictionary` -- CREATE TABLE IF NOT EXISTS `dictionary` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `lang` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; -- -------------------------------------------------------- -- --   `word` -- CREATE TABLE IF NOT EXISTS `word` ( `id` int(11) NOT NULL AUTO_INCREMENT, `value` varchar(50) NOT NULL, `description` varchar(255) DEFAULT NULL, `dictionary_id` int(11) NOT NULL, `length` smallint(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `value` (`value`), KEY `dictionary_id` (`dictionary_id`), KEY `lenght` (`length`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; -- -------------------------------------------------------- -- --   `word_pseudo` -- CREATE TABLE IF NOT EXISTS `word_pseudo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `value` varchar(50) NOT NULL, `word_id` int(11) NOT NULL, `deleted_symbol_pos` smallint(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `value_word_id` (`deleted_symbol_pos`,`value`,`word_id`), KEY `word_id` (`word_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT= 1 ; 


, 1 5 .

2)


, , 2 , - SELECT . MySQL- . , , . .

DictionaryMysqlMapper
  ... private $_cachedWords; private $_cachedWordKeys; ... /** *        * * @param string $key  ()  * @return string|false|null */ public function GetWord($key) { if (isset($this->_cachedWords[$key])) { return $this->_cachedWords[$key]; } $wordRow = $this->_db->FetchOne("SELECT * FROM `word` WHERE `id` = " . $this->_db->QuoteValue($key)); $this->_cachedWords[$key] = $wordRow['value']; return $wordRow['value']; } 


3)


, , 100 50 . , 20 , 50.

. 1 0,5-0,6 .

だから

3- ( PHP 5.4, MySQL 5.5)

*
* , , « » )
* .
*




, .
,


ずおも
:
—
!
() , « »


たずめ


PHP 5.4 + MySQL 5.5, 0,5 . 9 :

  'from' => "" 'to' => "" 'runMode' => "MySQL" 'list' ... '0' => "" '1' => "" '2' => "" '3' => "" '4' => "" '5' => "" '6' => "" '7' => "" '8' => "" 'timeLoad' => ",  : 0,008000 ." 'time' => "   : 0,551032 ." 'status' => "." 

, PHP ( 100 ), . , , .

次は


, , . :



 , . , , Diamond-Square .

PS
, , .

! - . ご枅聎ありがずうございたした。

Source: https://habr.com/ru/post/J270845/


All Articles