網膜、56 37バイト
このソリューションは、必要なすべての入力値で機能します。
Retinaがこの課題で直面する最大の問題は、文字列の最大長が2 ^ 30文字であるため、数値(単項表現)を扱う通常の方法は2 ^ 30を超える値では機能しないという事実です。
この問題を解決するために、数値の一種の10進数表現を維持しながら別のアプローチを採用しましたが、各桁は単項で記述されています(この表現をdigitunaryと呼びます)。たとえば、数字341
は数字のように書かれ111#1111#1#
ます。この表現を使用して、最大2^30/10
桁数(最大1億桁)の数字を処理できるようになりました。任意の算術演算では標準の単項式ほど実用的ではありませんが、少しの努力であらゆる種類の演算を行うことができます。
注:理論上、桁数は他の基数を使用できます(たとえば、バイナリ110
は1#1##
基数2の桁数になります)が、Retinaには10進数と単項を変換する組み込み関数があり、他の基数を直接処理する方法がないため、10進数がおそらく最も扱いやすい基数です。
私が使用したアルゴリズムは、ゼロに達するまで2で連続した整数除算を行います。除算の数は、この数を表すのに必要なビット数です。
それでは、どのように数字を2で割るのでしょうか?これを行うRetinaスニペットを次に示します。
(1*)(1?)\1# We divide one digit, the first group captures the result, the second group captures the remainder
$1#$2$2$2$2$2 The result is put in place of the old number, the remainder passes to the next digit (so it is multiplied by 10) and is divided by two there -> 5 times the remainder goes to the next digit
この置換は、桁数を2で割るのに十分であり、元の数が奇数の場合、末尾から.5を削除するだけです。
したがって、完全なコードは次のとおりです。数字に数字が残るまで2で除算しn
、各反復で文字列の前にリテラルを配置しますn
。最後の数字が結果になります。
. |
$*1# Convert to digitunary
{`^(.*1) Loop:|
n$1 add an 'n'
(1*)(1?)\1# |
$1#$2$2$2$2$2 divide by 2
)`#1*$ |
# erase leftovers
n Return the number of 'n's in the string
オンラインでお試しください!
更新されたソリューション、37バイト
マーティン・エンダーのおかげで、長さの約3分の1をゴルフした多くの良いアイデアによる大きなリファクタリング!
主なアイデアは_
、単項記号として使用することです。この方法では、文字列に通常の数字を使用できます。_
では、必要なときに sに使用できます:これにより、分割および複数の挿入時に多くのバイトを保存できます桁。
コードは次のとおりです。
<empty line> |
# put a # before each digit and at the end of the string
{`\d Loop:|
$*_ Replace each digit with the corrisponding number of _
1`_ |
n_ Add an 'n' before the first _
__ |
1 Division by 2 (two _s become a 1)
_# |
#5 Wherever there is a remainder, add 5 to the next digit
}`5$ |
Remove the final 5 you get when you divide odd numbers
n Return the number of 'n's in the string
オンラインでお試しください!