Retina , 56 37 Bytes
Diese Lösung funktioniert mit allen erforderlichen Eingabewerten.
Das größte Problem, mit dem Retina bei dieser Herausforderung konfrontiert ist, ist die Tatsache, dass die Zeichenfolgen eine maximale Länge von 2 ^ 30 Zeichen haben. Daher funktioniert die übliche Art des Umgangs mit Zahlen (unäre Darstellung) nicht mit Werten über 2 ^ 30.
Um dieses Problem zu lösen, habe ich einen anderen Ansatz gewählt, bei dem eine Art Dezimaldarstellung von Zahlen beibehalten wurde , bei der jedoch jede Ziffer unär geschrieben ist (ich bezeichne diese Darstellung als Digitunary ). Zum Beispiel würde die Nummer 341
wie 111#1111#1#
im Digitunary geschrieben werden. Mit dieser Darstellung können wir jetzt mit Zahlen bis zu 2^30/10
Ziffern (~ 100 Millionen Ziffern) arbeiten. Es ist weniger praktisch als Standard für beliebige Arithmetik, aber mit ein wenig Aufwand können wir jede Art von Operation ausführen.
HINWEIS: Digitunary könnte theoretisch jede andere Basis verwenden (z. B. 110
wäre Binär 1#1##
in Base 2 Digitunary), aber da Retina über integrierte Funktionen zum Konvertieren zwischen Dezimal und Unär verfügt und keine direkte Möglichkeit besteht, mit anderen Basen umzugehen, ist Decimal wahrscheinlich die am besten handhabbare Basis.
Der Algorithmus, den ich verwendet habe, macht aufeinanderfolgende ganzzahlige Divisionen durch zwei, bis wir Null erreichen. Die Anzahl der Divisionen, die wir gemacht haben, ist die Anzahl der Bits, die zur Darstellung dieser Anzahl benötigt werden.
Also, wie teilen wir digital durch zwei? Hier ist das Retina-Snippet, das das macht:
(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
Dieser Ersatz reicht aus, um eine digitale Zahl durch 2 zu teilen. Wenn die ursprüngliche Zahl ungerade war, müssen wir nur mögliche .5s vom Ende entfernen.
Also, hier ist der vollständige Code, wir teilen ihn durch zwei, bis die Zahl noch Ziffern enthält, und setzen n
bei jeder Iteration ein Literal vor die Zeichenfolge: Die Zahl n
am Ende ist das Ergebnis.
. |
$*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
Probieren Sie es online!
Aktualisierte Lösung, 37 Bytes
Großes Refactoring mit vielen guten Ideen, die rund ein Drittel der Länge ausmachten, alles dank Martin Ender!
Die Hauptidee ist, _
als unäres Symbol zu verwenden: Auf diese Weise können wir reguläre Ziffern in unserer Zeichenfolge verwenden, solange wir sie _
bei Bedarf wieder in s konvertieren. Auf diese Weise können wir beim Teilen und beim Einfügen mehrerer Bytes viele Bytes einsparen Ziffern.
Hier ist der Code:
<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
Probieren Sie es online!