Retina , 56 37 byte
Questa soluzione funziona con tutti i valori di input richiesti.
Il problema più grande che Retina affronta in questa sfida è il fatto che le sue stringhe hanno una lunghezza massima di 2 ^ 30 caratteri, quindi il solito modo di trattare i numeri (rappresentazione unaria) non funziona con valori maggiori di 2 ^ 30.
Per risolvere questo problema ho adottato un approccio diverso, mantenendo una sorta di rappresentazione decimale dei numeri, ma in cui ogni cifra è scritta in modo unario (chiamerò questa rappresentazione digitale ). Ad esempio il numero 341
sarebbe scritto come 111#1111#1#
in digitunary. Con questa rappresentazione ora possiamo lavorare con numeri fino a 2^30/10
cifre (~ cento milioni di cifre). È meno pratico di unario standard per l'aritmetica arbitraria, ma con un po 'di sforzo potremmo fare qualsiasi tipo di operazione.
NOTA: il digitunary in teoria potrebbe usare qualsiasi altra base (es. Binario 110
sarebbe 1#1##
in digitunary di base 2), ma poiché Retina ha builtin per convertire tra decimale e unario e nessun modo diretto per gestire altre basi, il decimale è probabilmente la base più gestibile.
L'algoritmo che ho usato sta facendo divisioni intere successive per due fino a raggiungere lo zero, il numero di divisioni che abbiamo creato è il numero di bit necessari per rappresentare questo numero.
Quindi, come possiamo dividere per due in digitunary? Ecco lo snippet Retina che lo fa:
(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
Questa sostituzione è sufficiente per dividere un numero digitunary per 2, dobbiamo solo rimuovere eventuali 0,5 secondi dalla fine se il numero originale era dispari.
Quindi, ecco il codice completo, continuiamo a dividere per due finché non ci sono ancora cifre nel numero e mettiamo un letterale n
davanti alla stringa ad ogni iterazione: il numero di n
alla fine è il risultato.
. |
$*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
Provalo online!
Soluzione aggiornata, 37 byte
Grande refactoring con molte buone idee che hanno giocato a golf per circa un terzo della lunghezza, tutto grazie a Martin Ender!
L'idea principale è quella di usare _
come nostro simbolo unario: in questo modo possiamo usare cifre regolari nella nostra stringa, purché le riconvertiamo in _
s quando è necessario: questo ci consente di salvare molti byte sulla divisione e sull'inserimento di più cifre.
Ecco il codice:
<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
Provalo online!