Retina , 56 37 bytes
Esta solução funciona com todos os valores de entrada necessários.
O maior problema que Retina enfrenta nesse desafio é o fato de suas seqüências terem um comprimento máximo de 2 ^ 30 caracteres, portanto, a maneira usual de lidar com números (representação unária) não funciona com valores maiores que 2 ^ 30.
Para resolver esse problema, adotei uma abordagem diferente, mantendo uma espécie de representação decimal dos números, mas onde cada dígito é escrito em unário (chamarei essa representação de digitunário ). Por exemplo, o número 341
seria escrito como 111#1111#1#
num dígito. Com essa representação, agora podemos trabalhar com números de até 2^30/10
dígitos (~ cem milhões de dígitos). É menos prático que o padrão unário para aritmética arbitrária, mas com um pouco de esforço, poderíamos realizar qualquer tipo de operação.
OBSERVAÇÃO: em teoria, o digitunary poderia usar qualquer outra base (por exemplo, o binário 110
estaria 1#1##
na base 2 do digitunary), mas, como o Retina possui builtins para converter entre decimal e unário e nenhuma maneira direta de lidar com outras bases, o decimal é provavelmente a base mais gerenciável.
O algoritmo que usei faz divisões inteiras sucessivas por dois até chegarmos a zero, o número de divisões que criamos é o número de bits necessários para representar esse número.
Então, como é que vamos dividir por dois em dois dígitos? Aqui está o trecho de Retina que faz isso:
(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
Essa substituição é suficiente para dividir um número digitunário por 2; basta remover 0,5s possíveis do final, se o número original for ímpar.
Então, aqui está o código completo, continuamos dividindo por dois até que ainda haja dígitos no número e colocamos um literal n
na frente da string a cada iteração: o número de n
no final é o 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
Experimente online!
Solução atualizada, 37 bytes
Grande refatoração com muitas boas idéias que jogaram cerca de um terço do comprimento, tudo graças a Martin Ender!
A idéia principal é usar _
como símbolo unário: dessa maneira, podemos usar dígitos regulares em nossa string, desde que os convertamos de volta para _
s quando necessário: isso permite salvar muitos bytes na divisão e na inserção de múltiplos dígitos.
Aqui está o 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
Experimente online!