Обчисліть n-й член послідовності самоопису Голомба


11

Натхненний попереднім запитанням .

Самоописуюча послідовність Голомба g (n) - це послідовність, де будь-яке натуральне число nповторюється в послідовності g (n) разів.

Перші кілька номерів у такій послідовності:

n    1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20
g(n) 1  2  2  3  3  4  4  4  5  5  5  6  6  6  6  7  7  7  7  8

Видно, що g (4) = 3, і що "4" повторюється 3 рази в послідовності.

Дано вхід n, вихід g(n).

Обмеження: n <100000.

Найменший код виграє.


Для наївних підходів це те саме, що і попереднє питання, за винятком того, що він використовує, nа не 2 - n % 1. Чи є у вас якісь причини очікувати, що відповіді будуть суттєво різними?
Пітер Тейлор

2
У Haskell ви можете скористатися цим:golomb=1:2:2:concat(zipWith replicate(drop 2 golomb)[3..])
FUZxxl

@PeterTaylor: Я цього не знав.
beary605

Відповіді:


5

GolfScript (31 знак)

~([1 2.]2{.2$=[1$)]*@\+\)}3$*;=

Демо


Добре, але чи справді ви пробували це з n = 99999, і якщо так, то скільки часу це зайняло? (Коли я спробував це, він пробіг протягом години, перш ніж потрапити на ліміт пам’яті 100 МіБ, який я встановив би за нього, і зазнав аварії.)
Ільмарі Каронен

@IlmariKaronen, ні. Питання не встановлює жодних обмежень щодо пам’яті та ефективності часу, тому я припускаю, що обмежений розмір вводу призначений для тих мов, які мають вбудовану фіксовану ширину.
Пітер Тейлор

6

Желе , не конкуруючий

10 байт Ця відповідь не є конкурентоспроможною, оскільки виклик передує створенню желе.

’ßßạ¹ß‘µṖ¡

Для цього використовується рекурсивна формула a (1) = 1, a (n + 1) = 1 + a (n + 1 - a (a (n))) зі сторінки OEIS.

Спробуйте в Інтернеті!

Як це працює

’ßßạ¹ß‘µṖ¡ Main link. Input: n

’          Decrement; yield n - 1.
 ßß        Recursively call the main link twice, with argument n - 1.
   ạ¹      Take the absolute difference of a(a(n - 1)) and n.
     ß     Recursively call the main link, with argument n - a(a(n - 1)).
      ‘    Increment the result, yielding 1 + a(n - a(a(n - 1))).
       µ   Combine the chain to the left into a single link.
        Ṗ  Pop [1, ..., n]. This yields [] iff n == 1.
         ¡ Execute the chain iff Ṗ returned a non-empty array.

4

PHP - 63 символів

function g($n){for(;++$i<=$n;){for(;++$j<=$i;){echo $i;}$j=0;}}

Швидкий І короткий.

Здається, я мав на увазі неправильну послідовність. Дерп.

Це ПРАВИЛЬНО, швидко та коротко.

function g($n){for(;++$i<$n;){echo round(1.201*pow($i,.618));}}

Точність може постраждати від необхідних 100 000 знаків, але я насправді відповідав оцінці.


3

PHP

Ця рекурсивна версія коротша (60), але обчислювально неефективна:

function g($n){return$n==1?1:1+g($n-g(g($n-1)));}echo g($n);

Це набагато швидше, але довше (78):

$a=[1,2,2];for($i=3;$i<$n;$i++)for($j=0;$j<$a[$i-1];$j++)$a[]=$i;echo$a[$n-1];

Набагато швидше, але на 89 символів було б:

$a=[1,2,2];for($i=3;!isset($a[$n-1]);$i++)for($j=0;$j<$a[$i-1];$j++)$a[]=$i;echo$a[$n-1];

Що є O (n)



3

Оазис , 7 байт (не конкуруючий)

Код:

n<aae>T

Спробуйте в Інтернеті!

Оазис - мова, розроблена Аднаном, яка спеціалізується на послідовностях.

В даний час ця мова може виконувати рекурсію і закриту форму.

В Tкінці - це скорочення для 10, що вказує на те, що a(0) = 0і a(1) = 1. Щоб додати більше тестів, просто додайте їх до списку в кінці.

n<aae>T
n<aae>10  expanded

       0  a(0) = 0
      1   a(1) = 1

n         push n (input)
 <        -1
  a       a(above)  [a is the sequence]
   a      a(above)
    e     a(n-above)
     >    +1

Зараз ми по суті розрахували a(n-a(a(n-1))+1.


2

Perl, 48 чол

(@a=(@a,($,)x($a[$,++]||$,)))<$_?redo:say$,for<>

Вхід на stdin, вихід на stdout. Потрібно Perl 5.10 або новішої версії та -M5.010увімкнути sayфункцію. Займає час O ( n 2 ) через неефективну маніпуляцію масивом, але все ще досить швидку, щоб легко обчислити до 100 000-го терміну.



2

Пітон - 64 символи

n=input()
g=[1,2,2]
for i in range(3,n):g+=[i]*g[i-1]
print g[n]

1
Це мило. Я не думав, що це [i]*g[i-1]зробить це, тому я схилився назад, щоб зробити це іншим способом; Я думав, що це поводитиметься більше, як чомусь множення матриці на скаляр ...
chucksmash


1

J, 43 символи

f=:3 :'<.@:+&0.5(p^2-p)*y^p-1[p=:(+%)/20$1'

Визначає функцію, використовуючи асимптотичний вираз, наведений на сторінці вікіпедії.

   f 5
3
   f 20
8
   f 100000
1479

Прикро 9 символів використовуються лише для округлення до найближчого цілого числа.


1

Прелюдія , 69 55 54 байт

?1-(v  #1)-
1   0v ^(#    0 (1+0)#)!
    (#)  ^#1-(0)#

Якщо використовується стандартний сумісний інтерпретатор, він приймає введення та вихід як значення байтів . Щоб фактично використовувати десяткові числа на STDIN / STDOUT, вам знадобиться інтерпретатор Python з NUMERIC_OUTPUT = Trueі додаткова опція NUMERIC_INPUT = True.

Пояснення

Скелет програми є

?1-(    1 -
1                     )!

Ми читаємо вхід Nна перший голос і зменшуємо його, щоб отримати N-1. Ми також ініціалізуємо другий голос на 1. Потім обводимо цикл N-1один раз, кожна ітерація якого отримує наступне значення послідовності на другому стеку. В кінці друкуємо Nй число.

Ідея програми полягає в тому, щоб поставити кожен елемент послідовності в чергу на третій голос і зменшити голову цієї черги в кожній ітерації. Коли голова досягне 0, ми збільшуємо значення послідовності і видаляємо її 0.

Тепер проблема полягає в тому, що Prelude використовує стеки, а не черги. Тому нам потрібно трохи зрушити цей стек, щоб використовувати його, як чергу.

v  #
0v ^
(#)

Це копіює поточне значення послідовності в перший голос (як тимчасова копія), натискає 0на другий голос (щоб позначити кінець черги). А потім виконує цикл для переміщення (і тим самим зворотного) третього стека на другий. Після циклу ми поміщаємо копію поточного значення послідовності поверх другого стека (який є хвостом нашої черги).

 )
(#
 ^#1-

Це виглядає трохи некрасиво, але по суті це петля, яка зміщує стек назад на третій голос. Оскільки значення )знаходиться в тому ж стовпці, що й інструкції з переміщення, 0ми ставимо другий голос раніше і в кінці третього голосу, тому нам потрібно видалити його з іншим #. Потім декрементуйте верхню частину 3-го голосу, тобто голову черги.

Тепер це стає трохи прикро - ми хочемо запустити якийсь код, коли це значення 0, але єдина контрольна структура (цикл) Prelude відповідає лише на ненульові значення.

 0 (1+0)#
(0)#

Зауважте, що вершина другого голосу є правдоподібною (оскільки послідовність Голомба не містить жодних 0s). Тож навантаження переходить у цей голос (остання пара дужок). Нам просто потрібно не допустити цього, якщо голова черги ще не 0є. Отже, спочатку у нас є "петля" на третьому голосі, яка натискає 0на другий голос, якщо голова черги ще не дорівнює нулю. Ми також ставимо 0третій голос, щоб негайно вийти з циклу. Тоді #третій голос або видаляє це 0, або видаляє голову черги, якщо це вже було нульовим. Тепер цей другий цикл вводиться лише в тому випадку, якщо голова черги була нульовою (і0на другий голос ніколи не штовхався). У цьому випадку ми збільшуємо поточне значення послідовності і натискаємо a, 0щоб вийти з циклу. Нарешті, 0на вершині стеку завжди буде вершина, яку нам потрібно відкинути.

Я сказав вам, що логічне заперечення дратує в Прелюдії ...



1

CJam, 14 байт

CJam набагато молодший за цей виклик, тому ця відповідь не відповідає зеленій галочці. Однак, досить рідко ви отримуєте jце прекрасно використовувати , тому я хотів опублікувати це все одно.

l~2,{_(jj-j)}j

Тестуйте це тут.

Пояснення

jв основному є "запам'ятовуваним оператором рекурсії". Це займає ціле число N, масив і блок F. Масив використовується для ініціалізації пам’яті: елемент в індексі iбуде повернутий для F(i). jпотім обчислює F(N)або переглянувши його, або запустивши блок (зі nстеком), якщо значення ще не запам’ятовується. Дійсно чудова особливість полягає в тому, що всередині блоку jприймається лише ціле число iі викликає F(i)рекурсивно. Отже ось код:

l~             "Read and eval input.";
  2,           "Push a 2-range onto the stack, i.e. [0 1]. The first value is irrelevant
                but the second value is the base case of the recursion.";
    {       }j "Compute F(N).";
     _(        "Duplicate i and decrement to i-1.";
       jj      "Compute F(F(i-1)).";
         -     "Subtract from i.";
          j    "Compute F(n-F(F(i-1))).";
           )   "Increment the result.";

1

J, 16 байт

    <:{1($1+I.)^:[~]

    (<:{1($1+I.)^:[~]) every 1+i.20  NB. results for inputs 1..20
1 2 2 3 3 4 4 4 5 5 5 6 6 6 6 7 7 7 7 8

Це рішення в значній мірі базується на рішенні algorithmshark в аналогічне завдання. Ви можете знайти пояснення щодо цього методу там.

J, 33 байти

У цьому підході я будую послідовність h(k)зі значеннями перших індексів, iде g(i)=kтак h = 1 2 4 6 9 12 16.... Ми можемо отримати h(k)досить просто h(1..k-1)з виразу, ({:+1+[:+/#<:])де знаходиться вхід h(1..k-1).

Обчислення результатів від hпростого.h ([:+/]>:[) input

[:+/]>:1 2(,{:+1+[:+/#<:])@]^:[~]


0

Пітон - 76 символів

n=20;g=[1,2,2];[[g.append(i)for j in range(g[i-1])]for i in range(3,n)];g[n]

Це фактично заповнює список купою Nones. Здається, «правильний» розмір Nones Тхо :)
daniero

1
@Daniero Так, це наче дивний код. Мені довелося запустити його кілька разів, щоб переконати себе, що це насправді спрацювало. Він заповнює розуміння списку купою Nones, оскільки list.append () повертає Noneтип. Я просто використав розуміння вкладеного списку, щоб досягти вкладеного циклу. Єдина мета розуміння списку тут - змусити код
циклікувати

Це економить два символи, якщо я зробив традиційні вкладені петлі :)
chucksmash

На жаль, здається, ви жорстко кодуєте вхід, який ми не дозволяємо, і припускаєте середовище REPL, що зробило б цей фрагмент. За замовчуванням усі подання повинні бути повноцінними програмами або функціями, які використовують один із наших методів вводу / виводу за замовчуванням, а не фрагменти. Повідомте мене, якщо у вас є питання.
Алекс А.

@AlexA. Займаєтесь трохи археологією?
chucksmash

0

JavaScript - 48 символів

for(g=[,i=j=k=1,2];i<1e5;k=--k?k:g[++j])g[i++]=j

Створює 1-індексований масив, gщо містить значення послідовності.

Редагувати - JavaScript - 46 символів

v=[,1];for(x=2;x<1e5;)v[x]=1+v[x-v[v[x++-1]]]

Створює 1-індексований масив, vщо містить значення послідовності.

Правка 2 - ECMAScript 6 - 27 символів

g=x=>x-1?1+g(x-g(g(x-1))):1

Перші два досить швидко - третій дуже повільний


0

Haskell, 63 байти

f n|n<3=n|n<4=2|1>0=foldr1(++)[replicate(f m)m|m<-[1..]]!!(n-1)

Це наївний підхід, я не знав про дуже короткий повтор, коли писав це, але думав, що все-таки опублікую це, навіть якщо він довший, ніж усі інші реалізації Haskell, наприклад,

Обчисліть n-й член послідовності самоопису Голомба

і

https://codegolf.stackexchange.com/a/23979/24877

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.