パリンドロームの検索に行く

少し前にHabréでhexlet.ioからcodebattleに関する記事がありました。 まあ、それは友人と一緒に私たちを引きずりました、それは麻薬のようなものです! あなたは仕事に気を取られようとしているようで、あなたの手は直接サイトに行くように描かれており、すべての考えはソリューションの最適化に関するものです。

そして、ある日問題が発生したとき、次のように聞こえました。「10進数585は2進数で1001001001です。 それは両方のベースでパリンドロームです。 n番目の回文数を見つけます。 ロシア語の場合、次のようになります。「バイナリ形式の10進数585は、1001001001のように見えます。これは、両方の数値システムの回文です。 n番目の類似の回文を見つけます。 それはまったく複雑ではなく、すぐに解決されました。

function is_palindrome($num) { return $num == strrev($num); } function solution($num) { $count = $i = 0; while($count<$num) { $i++; //     ,          if (is_palindrome($i) && is_palindrome(decbin($i))){ $count++; } } return $i; } 

しかし、これは不運です。 その頃、ウェブサイトはハラエフェクトに攻撃され、テストは合格したくなく、タイムアウトで落ちました。 ローカルチャットで、ソリューションの最適化に関する議論が始まりましたが、実際的なアドバイスはありませんでした。 その後、サイトは手放し、すべてのテストは合格しましたが、最適化への欲求は残りました...

10進パリンドロームを生成します


そもそも、タイプライターでパリンドロームをどれだけ見つけることができるのかと思っていました。 チャットでは22個以上を検索するように勧められていませんでしたが、わずか5秒で落ち着いて27個を見つけましたが、次のものは4分以上たってから届きました。 私はそれ以上待たなかった-長い間何か。 最適化を開始するために、回文についてさらに学ぶことにしました。

いくつかのピースを生成し、検討し始めました。

パリンドローム
  1. 1
  2. 3
  3. 5
  4. 7
  5. 9
  6. 33
  7. 99
  8. 313
  9. 585
  10. 717
  11. 7447
  12. 9009
  13. 15351
  14. 32223
  15. 39993
  16. 53235
  17. 53835
  18. 73737
  19. 585585
  20. 1758571


実際、数値パリンドロームは特定の番号であり、同じ番号の末尾に取得、ミラーリング、およびアタッチされます。 つまり 彼らは数字235を取得し、それをミラーリングし、532を取得して接続しました。それは美しい回文であることが判明しました-235532。 すぐに言ってやった!

 function solution($num) { $count = $i = 0; while($count<$num) { $i++; //            $palindrome = $i . strrev($i); //            . if (is_palindrome(decbin($palindrome))) { $count++; } } return $palindrome; } 

開始すると、1文字の回文が欠落していることがわかり、最初の9つの数字に単純なサイクルが追加されました。

 for ($i = 1; $i < 10; $i++) { if (is_palindrome(decbin($i))) { $count++; if ($count == $num) return $i; } } 

もう一度実行してみると、私の間違いがはるかに強いことがわかりました。 313、585、717などの奇数の文字を含む回文を完全に忘れてしまいました! そしてここで私は一生懸命に考えなければなりませんでした。 受信したパリンドロームのリストを見ると、記号の数が奇数のパリンドロームは、同じ偶数のパリンドロームであり、中央の記号だけがあることがわかります。 つまり 偶数回文を作成し、中央に1〜9の数字を挿入して出来上がり-奇数回文を作成します。 しかし! このループにそれらを挿入すると、数字の順序が失われます。 そのため、コードに根本的な変更を加え、文字数に基づいて構築する必要がありました。

 function solution($num) { $count = 0; //  . for ($i = 1; $i < 10; $i++) { if (is_palindrome(decbin($i))) { $count++; if ($count == $num) return $i; } } $p_size = 1; while (true) { $min = 10**($p_size-1); $max = (10**$p_size)-1; // $min  max          for ($i = $min; $i <= $max; $i++) { //     -  $palindrome = $i . strrev($i); //       . if (is_palindrome(decbin($palindrome))) { $count++; if ($count == $num) return $palindrome; } } for ($i = $min; $i <= $max; $i++) { for ($j = 0; $j < 10; $j++) { //     -  $palindrome = $i . $j . strrev($i); //       . if (is_palindrome(decbin($palindrome))) { $count++; if ($count == $num) return $palindrome; } } } $p_size++; } } 

実際、ここではすべてが簡単です。 まず、1〜9の1桁の数字を使用します。 2桁の回文を作成します。 以下は3桁です。 次に、ランクを上げて10〜99の数字を取得します。 4桁と5桁の回文が判明します。 まあ、など

テスト中!


最初に、28回目の回文を調べ始めました。 改善された機能のために、これは絶対に些細な作業であることが判明しました。 28日は0.15秒で受信されました! これは、速度が1,500倍以上に増加したことを意味します。 嬉しかった。 5秒で40回以上の回文を取得できました。 50分は2.5分で受信されました。

結果として生じるパリンドロームに注意を払って、私はそれらがすべて奇妙であることに気づきました。 そして真実は! バイナリ形式の10進パリンドロームでさえも0で終わり、常に1で始まるため、パリンドロームにもなり得ません。 これは、チェックする必要さえないことを意味します。 また、回文を生成するため、最初の偶数桁の数字をすべてスキップできます。

単純な継続は、条件付きですぐに却下しました。 私たちがそれらを循環させることは意味がありません。 それらをめくります。 いくつかのオプションを試しました:

 if(!(substr($i,0,1))%2)) $i += $min; 

 if(!((floor($i/$min))%2)) $i += $min; 

 if (!$limit){ $limit = $min; $i += $min; } $limit--; 

私は後者を最速として解決し、このコードを得ました。

完全なコード
 function solution($num) { $count = 0; //  . for ($i = 1; $i < 10; $i++) { if (is_palindrome(decbin($i))) { $count++; if ($count == $num) return $i; } } $p_size = 1; while (true) { $min = 10**($p_size-1); $max = (10**$p_size)-1; // $min  max          $limit = $min; for ($i = $min; $i <= $max; $i++) { //         if (!$limit){ $limit = $min; $i += $min; } $limit--; //     -  $palindrome = $i . strrev($i); //       . if (is_palindrome(decbin($palindrome))) { $count++; if ($count == $num) return $palindrome; } } $limit = $min; for ($i = $min; $i <= $max; $i++) { if (!$limit){ $limit = $min; $i += $min; } $limit--; for ($j = 0; $j < 10; $j++) { //     -  $palindrome = $i . $j . strrev($i); //       . if (is_palindrome(decbin($palindrome))) { $count++; if ($count == $num) return $palindrome; } } } $p_size++; } } 


これにより、約2倍の加速が得られました。 50秒は88秒で受信され、私の意見では、素晴らしい結果でした!

バイナリパリンドロームを生成します


これで、バイナリパリンドロームを形成しようと考えたので、停止して喜んで準備ができました。 そして何? 使用される数字が少ないため、偶数であってもできません。 周りのいくつかのプラス!

少し考えて、私はすぐにコードを変更し、次のものを得ました:

 function solution($num) { if ($num==1) return 1; $count = 1; $p_size = 1; while (true) { $min = 2**($p_size-1); $max = (2**$p_size)-1; // $min  max             for ($i = $min; $i <= $max; $i++) { $half_palindrome = decbin($i); //     -     $bin_palindrome = ($half_palindrome) . strrev($half_palindrome); //       . $dec_palindrome = bindec($bin_palindrome); if (is_palindrome($dec_palindrome)) { $count++; if ($count == $num) return $dec_palindrome; } } for ($i = $min; $i <= $max; $i++) { $half_palindrome = decbin($i); for ($j = 0; $j < 2; $j++) { //     -     $bin_palindrome = $half_palindrome . $j . strrev($half_palindrome); //       . $dec_palindrome = bindec($bin_palindrome); if (is_palindrome($dec_palindrome)) { $count++; if ($count == $num) return $dec_palindrome; } } } $p_size++; } } 

テストの後、私はすべてが正しく行われたことに気付きました。 28秒は0.05秒で受信されました。 48秒で50番目。 この仕事を引き受けたとき、私はそのような結果をまったく期待していませんでした。

それから私はすでにそれで十分だと決めました:私はすでにすべての期待を超えました。 嘘をついていますが、もちろん。 それから彼は速度をさらに上げる方法を考えようとしましたが、何も思い浮かびませんでした。 すでに疲れていて、夜は庭で。

そして最後に、要約表:

要約表
いやパリンドローム検索(秒)Palindrome dec generation(秒)パリンドロームビン生成(秒)ビット数
116.9141387939453E-65.0067901611328E-61
235.1975250244141E-54.887580871582E-54.2200088500977E-52
355.8889389038086E-55.5074691772461E-56.0081481933594E-53
476.4849853515625E-56.103515625E-56.6041946411133E-53
596.9856643676758E-56.6041946411133E-57.4148178100586E-54
6338.2969665527344E-57.1048736572266E-59.0122222900391E-56
7990.000112056732177738.6069107055664E-50.000102996826171887
83130.000205039978027340.000103950500488280.000126123428344739
95850.000330924987792970.000123977661132810.0001451969146728510
107170.00039696693420410.000130891799926760.000152111053466810
1174470.00266098976135250.00018286705017090.0002791881561279313
1290090.00319600105285640.000203847885131840.0003011226654052714
13153510.00534605979919430.00028991699218750.0003499984741210914
14322230.0111649036407470.000383853912353520.000477075576​​7822315
15399930.0138409137725830.000486850738525390.0005211830139160216
16532350.0183570384979250.000535964965820310.0005710124969482416
17538350.0185859203338620.000546932220458980.000589132308959916
18737370.0252549648284910.000660896301269530.0006551742553710917
195855850.196464061737060.00116705894470210.001551151275634820
2017585710.592638015747070.00260591506958010.002489089965820321
2119343910.652742862701420.0028920173645020.002650022506713921
2219797910.668315887451170.00298500061035160.002700090408325221
2331292131.05898594856260.003234863281250.003252029418945322
2450717051.72170996665950.00467300415039060.004043102264404323
2552595251.78634786605830.00498294830322270.004142045974731423
2658414851.98603796958920.00591897964477540.004393100738525423
27135005314.59910106658940.00979089736938480.006405115127563524
28719848917254.434272050860.0748970508575440.04632616043090830
29日9103730190.0909988880157470.05125713348388730
309394749390.0961220264434810.0520281791687030
3112908809210.112391948699950.06114697456359931
3274511115470.169254064559940.1551511287689233
33100509050010.199224948883060.1806252002716134
34184621264810.363782882690430.238993167877235
35324792974230.44276499748230.3330211639404335
36750151510570.887769937515260.4871730804443437
371109488490111.209517955780.6090040206909237
381365255256311.26376104354860.6963500976562537
3912341040143212.69412398338322.028050184249941
4014138999831413.07818007469182.186210155487141
4114749222947413.20892286300662.240367174148641
4217927040729713.88743686676032.519950151443541
4317940969049713.89042305946352.52121019363441
4419999252999914.32877802848822.701833009719841
4556526222625657.98124790191654.444355010986343
4672275262572279.2854259014135.142831087112443
4772847171748279.41209888458255.168857097625743
48948487478484912.1002409458165.99822020530744
493414138831414316.40152192115811.61456513404845
5055221253521225587.53703188896249.89753913879449
51933138363831339134.5680198669462.4961440563250
521793770770773971171.4510390758590.22687101364151
533148955775598413180.56048107147119.8572452068352
5410457587478575401293.4983189106224.4536139965154
5510819671917691801303.29767894745227.3886291980754
5618279440804497281506.18344306946287.7762150764555
5734104482028440143410.0452971458455
5837078796869787073428.895541191156
5937629927072992673431.1542971134256
6055952637073625955506.288716077856


PS。 ilyanikによる最適化の継続については、 この記事をご覧ください

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


All Articles