Retina , 56 37 bytes
Esta solución funciona con todos los valores de entrada requeridos.
El mayor problema que enfrenta Retina en este desafío es el hecho de que sus cadenas tienen una longitud máxima de 2 ^ 30 caracteres, por lo que la forma habitual de tratar con números (representación unaria) no funciona con valores mayores de 2 ^ 30.
Para resolver este problema, adopté un enfoque diferente, manteniendo una especie de representación decimal de números, pero donde cada dígito está escrito en unario (llamaré a esta representación digitalunaria ). Por ejemplo, el número 341
se escribiría como 111#1111#1#
en digitunary. Con esta representación ahora podemos trabajar con números de hasta 2^30/10
dígitos (~ cien millones de dígitos). Es menos práctico que el unario estándar para la aritmética arbitraria, pero con un poco de esfuerzo podríamos hacer cualquier tipo de operaciones.
NOTA: digitunary en teoría podría usar cualquier otra base (por ejemplo, el binario 110
estaría 1#1##
en base 2 digitunary), pero dado que Retina tiene incorporados para convertir entre decimal y unary y no hay una forma directa de tratar con otras bases, el decimal es probablemente la base más manejable.
El algoritmo que utilicé es hacer divisiones enteras sucesivas por dos hasta que lleguemos a cero, el número de divisiones que hicimos es el número de bits necesarios para representar este número.
Entonces, ¿cómo dividimos por dos en dígitosunarios? Aquí está el fragmento de Retina que lo hace:
(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
Este reemplazo es suficiente para dividir un número digital numérico por 2, solo necesitamos eliminar posibles .5s del final si el número original era impar.
Entonces, aquí está el código completo, seguimos dividiendo por dos hasta que todavía hay dígitos en el número, y ponemos un literal n
frente a la cadena en cada iteración: el número n
al final es el resultado.
. |
$*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
Pruébalo en línea!
Solución actualizada, 37 bytes
Gran refactorización con muchas buenas ideas que jugaron alrededor de un tercio de la longitud, ¡todo gracias a Martin Ender!
La idea principal es usar _
como nuestro símbolo unario: de esta manera podemos usar dígitos regulares en nuestra cadena, siempre y cuando los convertimos de nuevo a _
s cuando sea necesario: esto nos permite guardar muchos bytes en la división y en la inserción de múltiples dígitos
Aquí está el código:
<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
Pruébalo en línea!