Це рішення працює з усіма необхідними вхідними значеннями.
Найбільшою проблемою, з якою стикається Ретіна в цьому виклику, є той факт, що її рядки мають максимальну довжину 2 ^ 30 символів, тому звичайний спосіб поводження з числами (одинарне представлення) не працює зі значеннями, що перевищують 2 ^ 30.
Щоб вирішити цю проблему, я застосував інший підхід, зберігаючи своєрідне десяткове представлення чисел, але там, де кожна цифра написана одинаково (я називаю це представлення цифрова ). Наприклад, число 341
було б записане, як 111#1111#1#
у цифровій формі. За допомогою цього представлення ми тепер можемо працювати з числами до 2^30/10
цифр (~ сто мільйонів цифр). Він менш практичний, ніж стандартний уніар для довільної арифметики, але, доклавши трохи зусиль, ми могли б робити будь-які операції.
ПРИМІТКА: в цифрових системах теоретично може використовуватися будь-яка інша база (наприклад, двійковий 110
буде 1#1##
в базі 2, оцифрований), але оскільки 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, нам просто потрібно видалити можливі .5s з кінця, якщо початкове число було непарним.
Отже, ось повний код, ми продовжуємо ділити на два, поки не залишиться цифр у цифрі, і ставимо буквальне 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
Спробуйте в Інтернеті!