Retina , 56 37 bytes
Cette solution fonctionne avec toutes les valeurs d'entrée requises.
Le problème le plus important auquel Retina est confrontée dans ce défi est le fait que ses chaînes ont une longueur maximale de 2 ^ 30 caractères. Par conséquent, la manière habituelle de traiter les nombres (représentation unaire) ne fonctionne pas avec des valeurs supérieures à 2 ^ 30.
Afin de résoudre ce problème, j’ai adopté une approche différente en conservant une sorte de représentation décimale des nombres, mais où chaque chiffre est écrit en unaire (je vais appeler cette représentation numérique ). Par exemple, le nombre 341
serait écrit comme 111#1111#1#
dans digitunary. Avec cette représentation, nous pouvons maintenant travailler avec des nombres allant jusqu'à un 2^30/10
chiffre (environ cent millions de chiffres). C'est moins pratique que le unaire classique pour l'arithmétique arbitraire, mais avec un peu d'effort, nous pourrions faire n'importe quel type d'opération.
REMARQUE: digitunary pourrait théoriquement utiliser n'importe quelle autre base (par exemple binaire 110
serait 1#1##
en base 2 digitunary), mais puisque Retina a été conçu pour effectuer la conversion entre décimales et unaires et qu'il n'existe aucun moyen direct de traiter d'autres bases, la décimale est probablement la base la plus facile à gérer.
L'algorithme que j'ai utilisé consiste à faire des divisions entières successives par deux jusqu'à atteindre zéro, le nombre de divisions que nous avons fait est le nombre de bits nécessaires pour représenter ce nombre.
Alors, comment divisons-nous par deux en numérique? Voici l'extrait de la rétine qui le fait:
(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
Ce remplacement est suffisant pour diviser un nombre numérique par 2, il suffit d’enlever les .5 possibles à la fin si le nombre initial était impair.
Donc, voici le code complet, nous continuons à diviser par deux jusqu'à ce qu'il y ait encore des chiffres dans le nombre, et mettons un littéral n
devant la chaîne à chaque itération: le nombre n
à la fin est le résultat.
. |
$*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
Essayez-le en ligne!
Solution mise à jour, 37 octets
Grand refactoring avec beaucoup de bonnes idées qui ont golfé environ un tiers de la longueur, tout cela grâce à Martin Ender!
L’idée principale est d’utiliser _
comme symbole unaire: de cette manière, nous pouvons utiliser des chiffres normaux dans notre chaîne, à condition de les reconvertir en _
s lorsque cela est nécessaire: cela nous permet d’économiser de nombreux octets lors de la division et de l’insertion de multiples. chiffres.
Voici le 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
Essayez-le en ligne!