Retina , 56 37 байт
Это решение работает со всеми необходимыми входными значениями.
Самая большая проблема, с которой Retina сталкивается в этой задаче, заключается в том, что ее строки имеют максимальную длину 2 ^ 30 символов, поэтому обычный способ работы с числами (унарное представление) не работает со значениями, превышающими 2 ^ 30.
Чтобы решить эту проблему, я принял другой подход, сохраняя своего рода десятичное представление чисел, но где каждая цифра пишется в унарном порядке (я назову это представление цифрой ). Например, число 341
будет написано как 111#1111#1#
в цифре. С этим представлением мы можем теперь работать с числами до 2^30/10
цифр (~ сто миллионов цифр). Это менее практично, чем стандартное унарное для произвольной арифметики, но, приложив немного усилий, мы могли бы выполнять любые операции.
ПРИМЕЧАНИЕ: digitunary в теории может использовать любую другую базу (например, двоичная 110
будет 1#1##
в base 2 digitunary), но, поскольку Retina имеет встроенные функции для преобразования между десятичной и унарной и не имеет прямого способа иметь дело с другими базами, десятичная дробь, вероятно, является наиболее управляемой базой.
Алгоритм, который я использовал, состоит в том, чтобы делить последовательные целочисленные деления на два, пока мы не достигнем нуля, число делений, которое мы сделали, - это количество битов, необходимое для представления этого числа.
Итак, как мы можем разделить на два в цифре? Вот фрагмент Retina, который делает это:
(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
Этой замены достаточно, чтобы разделить цифровое число на 2, нам просто нужно удалить возможные .5 с конца, если исходное число было нечетным.
Итак, вот полный код, мы продолжаем делить на два до тех пор, пока в числе не останутся цифры, и ставим литерал n
перед строкой на каждой итерации: число n
в конце является результатом.
. |
$*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
Попробуйте онлайн!
Обновленное решение, 37 байт
Большой рефакторинг с множеством хороших идей, которые играли в гольф примерно на треть длины, все благодаря Мартину Эндеру!
Основная идея состоит в том, чтобы использовать в _
качестве нашего унарного символа: таким образом, мы можем использовать обычные цифры в нашей строке, если мы преобразуем их обратно в _
s, когда это необходимо: это позволяет нам экономить много байтов при делении и вставке нескольких цифры.
Вот код:
<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
Попробуйте онлайн!