Генерировать последовательность фигур Хофштадтера

16

В работе Гёделя, Эшера, Баха , Дуглас Хофштадтер вводит целочисленную последовательность, которую обычно называют последовательностью цифр:

2, 4, 5, 6, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, ...

Вам может понравиться разработка определения последовательности самостоятельно как часть задачи, но если вы не можете или не хотите выяснить это, вы можете найти его в OEIS как последовательность A030124 и чуть более четкое определение в Википедии .

Напишите программу или функцию, которая, учитывая n через STDIN, ARGV или аргумент функции, печатает список первых nчисел последовательности в STDOUT в любом приемлемом формате списка.

Это код гольф, выигрывает самое короткое решение в байтах.

Мартин Эндер
источник

Ответы:

6

CJam, 38 30 29 21 байт

li_3*,2>\{(_pX+:X-}*;

Попробуйте онлайн.

Как это устроено

li                     " Read an integer N from STDIN.              ";
  _3*,2>               " Push S := [ 2 3 ... (N * 3 - 1) ].         ";
        \{        }*   " Do the following N times:                  ";
          (            " Shift an integer I from S.                 ";
           _p          " Print a copy of I, followed by a linefeed. ";
             X+:X      " Execute X += I. (X is initialized to 1.)   ";
                 -     " Remove X from S.                           ";
                    ;  " Discard S from the stack.                  ";

Пример запуска

$ cjam <(echo 'li_3*,2>\{(_pX+:X-}*;') <<< 20
2
4
5
6
8
9
10
11
13
14
15
16
17
19
20
21
22
23
24
25
Деннис
источник
Вы пропустили s из aditsu при вводе URL-адреса для переводчика
Beta Decay
@BetaDecay тогда почему бы не отредактировать, чтобы исправить это;)
Мартин Эндер
@Martin Я не думаю, что у меня было достаточно представителей ...
Beta Decay
2
@BetaDecay Вы не делаете, но вы все равно можете предложить их (что даже дает вам 2 повторения, если они приняты).
Мартин Эндер
Я чувствовал себя таким умным, чтобы отыграть 8 дополнительных байтов своего кода. Тогда я понял, что теперь он делает то же самое, что и ответы от гистократа, Мэтсджойса и Питера Тейлора ...
Деннис
6

Haskell, 67 61 60 56 55 53 персонажа

g n=take n$2:4:h
a#(x:s)=[a..x-2]++x#s
h=5#scanl(+)8h

вернуться к первому алгоритму.

это решение вычисляет последовательность дополнения путем суммирования начальных элементов последовательности. затем он вычисляет последовательность как все числа между порядковыми номерами дополнения.

(#)это функция, которая вычисляет числа между последовательностью дополнения.
hэто сама последовательность.
gэто функция, которая отвечает на вопрос.

функция g определена так, чтобы просто взять необходимое количество элементов из h.

тонкости:

hна самом деле последовательность фигур фигуры за исключением первых 2 элементов.
вычисляется не последовательность дополнения, а последовательность дополнения с добавлением 1 для каждого элемента.
эти две тонкости являются причиной scanl(+)8h(которая представляет собой код последовательности дополнения (за исключением первых 2 элементов) с добавленными 1) 8. это для третьего элемента последовательности дополнения с 1 добавленным к нему.
причина, по которой вычисления не пропускают первые два элемента, заключается в том, что они добавлены gв 2:4:h.

пример:

>g 50
[2,4,5,6,8,9,10,11,13,14,15,16,17,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,57,58,59]
гордый хаскеллер
источник
5

Руби, 54 48

f=->n{x=1
b=*2..n*n
n.times{b-=[x+=p(b.shift)]}}

демонстрация

Изменить: Гольф это немного больше, как только я понял, что мне не нужно держать полную последовательность дополнения в памяти. Вот как это работает сейчас: мы используем xдля отслеживания наибольшее вычисленное число в последовательности дополнения, и bэто пул кандидатов для последовательности. nраз мы выводим наименьший оставшийся элемент bи добавляем его xдля вычисления следующего числа в последовательности дополнения. Затем мы удаляем оба числа из пула кандидатов, поэтому мы всегда выводим наименьшее число, которое еще не было добавлено ни к одной из последовательностей.

Трюки с Ruby-гольфом: лямбда-синтаксис Stabby короче, чем определение метода. Требование, чтобы выходные данные передавались в STDOUT, а не как возвращаемое значение, вдохновило меня использовать тот факт, что возвращаемое значение p(x)есть x, что я обычно не помню, потому что это не так в версии Ruby, используемой в Anarchy Golf.

histocrat
источник
1
Как это работает?
гордый haskeller
1
FWIW вы могли бы использовать 2..2*n. Я должен использовать, n*nпотому что я делаю эффективно, b = [x]^bпоэтому мне нужно, чтобы самый большой элемент bбыл больше, чем самое большое значение x, но вам b -= [x]просто требуется, чтобы он bсодержал максимально возможное значение выходной последовательности.
Питер Тейлор
4

GolfScript ( 24 21 байт)

~.3*,1>\{(\(.p@+\|}*;

Онлайн демо

Это началось совсем по- другому, но в конечном итоге , сходящихся на порт GolfScript из histocrat «s решение Руби перед Денисом сделал несколько предложений , которые принимают его в несколько ином направлении. В частности, печать чисел в том виде, в котором мы их идентифицируем, значительно экономит время, собирая их в массив для печати в конце; причина в том, что это означает, что ни в коем случае нам не нужно беспокоиться о более чем 3 элементах в стеке.

рассечение

~.3*,           # Eval input n, dup, multiply by 3, make list [0 1 ... 3n-1]
1>              # Discard 0, which is part of neither sequence
\{              # Execute n times: stack contains pool of numbers not yet seen
                # in either sequence and the first element of it is the next element of the
                # complement sequence
  (\(           #   Pop two numbers from the start of the pool: stack is
                #     pool[0] pool[2..max] pool[1]
  .p            #   Print pool[1]
  @+            #   Rotate pool[0] to top and add to pool[1]
  \|            #   Place pool[0]+pool[1] at the start of the pool and
                #   (this is the clever bit) remove it from later in the pool
}*
;               # Discard the unused remainder of the pool
Питер Тейлор
источник
Если вы замените ^на \-, вы можете заменить ).*на 3*. Это не спасет байты, но значительно сократит время выполнения и использование памяти. - Вы должны быть в состоянии сохранить один байт, сохраняя целое число сверху массива. Цикл будет иметь тот же счетчик байтов, но инициализация будет на один байт короче.
Деннис
2
Set union работает даже лучше, чем разница:~.3*,1>\{(\(.p@+\|}*;
Деннис
3

J - 28 символов

Функция принимает в nкачестве аргумента.

($+/\(-.~2+i.)&:>:+/)^:_&2 4

Мы запускаем функцию с nлевым аргументом в правый аргумент несколько раз, пока она не производит никаких изменений. Аргумент для начала - это список 2 4.

В самой функции мы берем частичные суммы +/\и полную сумму +/, а затем увеличиваем их оба с &:>:. Затем мы генерируем каждое целое число от 2 до единицы, превышающей полную sum ( 2+i.), и устанавливаем subtract ( -.) частичные суммы, оставляя более длинную последовательность цифр по определению. Наконец, мы сокращаем или циклически расширяем список до длины n.

Результатом является то , что 2 4становится 3 7, и это удаляется от 2..8ухода 2 4 5 6 8. После очередного раунда 2 4 5 6 8становится 3 7 12 18 26становится

2 4 5 6 8 9 10 11 13 14 15 16 17 19 20 21 22 23 24 25 27

Таким образом, мы многократно расширяем последовательность цифр. $Поведение длины просто нетривиальная экономия характера способ ждет последовательности вырасти до длины nили больше, и выводят nпервые значения , когда они перестают меняться. Нам также не нужно долго ждать: мы можем получить до 46336 терминов из четырех применений внутреннего глагола.

Та же функция в к:

  • к2, 37 символов: {{x#y@&~_lin[y:1+!1+/y;1+\y]}[x]/2 4}
  • к4, 36 символов: {{x#y@&~(y:2+!1+/y)in\:1+\y}[x]/2 4}
algorithmshark
источник
2

Ява - 183 158

Это было самое лучшее, что я когда-либо играл в гольф, и я горжусь этим! (Хотя это далеко не в верхней части графиков (потому что это Java))

Спасибо Питеру Тейлору за предложения

class f{public static void main(String[]a){int q=1,m=Byte.valueOf(a[0]),w=2,n[]=new int[m*m*2];for(n[q+=w]=1;m-->0;){System.out.println(w);for(;n[++w]>0;);}}}

больше -

public class f {
    public static void main(String[] a) {
        int q = 1, m = Byte.valueOf(a[0]), w = 2, n[] = new int[m * m * 2];
        for (n[q += w] = 1; m-- > 0;) {
            System.out.println(w);
            for (; n[++w] > 0;)
                ;
        }
    }
}
Стрейч маньяк
источник
Этот внутренний цикл for довольно впечатляюще запутан, но я думаю, что вы можете сэкономить несколько байтов. Byte.valueOfсохраняет три, и так как вопрос не определяет диапазон ввода, я думаю, что это должно быть приемлемым. Вне циклов, mиспользуется только для инициализации n, так что k++<mможет быть m-->0, устранение kполностью. int[] nможно инициализировать как int n[]и объединить с предыдущим инициализатором. nникогда не содержит значений, отличных от 1, так n[...]!=0может быть n[...]>0. Инициализатор может затем стать инициализатором первого forцикла.
Питер Тейлор
И если вы избавляетесь uи просто используете ++w, нет необходимости устанавливать n[q]или n[w]. Есть одна ошибка, которая заключается в том, что вы запускаете в конце nwhen m==2, что лучше всего исправить при инициализации n=new int[2*m*m], но я думаю, что она уменьшается до 157 байтов.
Питер Тейлор,
То, что я имел в виду, чтобы инициализатор стал частью инициализатора первого цикла for, это for(int q=1,w=2,m=...,n[]=...;m-->0;){...сохранение точки с запятой.
Питер Тейлор
1

Python 2 - 77 байт


Код:

n=input();x=1;b=range(2,n*n)
while n:v=b.pop(0);x+=v;print v;b.remove(x);n-=1

Работает так же, как и решение @ histocrat, за исключением того, что ввод поступает из stdin.

matsjoyce
источник
1

Python 2 - 68

R=[1]
s=0
n=input()
while n:s+=1+(s+1in R);R+=[R[-1]+s];print s;n-=1
Фалько
источник
0

Желе , 15 байт

SƤŻ‘µṀ‘Rḟ
2dz¡ḣ

Попробуйте онлайн!

Ошибка памяти на входе 6.

Как это устроено

SƤŻ‘µṀ‘Rḟ  Aux. link (monad). Input: part of the desired sequence
SƤŻ‘       Sum of prefixes, then prepend a zero and increment
           This is a list of numbers to exclude from the next iteration
    µ      Re-focus on the above
     Ṁ‘Rḟ  Create range 1..Max + 1, then remove all elements of the above
           +1 is needed to progress from [2] to [2,4]

2dz¡ḣ  Main link (monad). Input: n, number of terms
2dz¡   Starting from 2, apply aux. link n times
    ḣ  Take n elements from the beginning

Более эффективная версия, 16 байт

SƤŻ‘µṀ‘Rḟḣ³
2ÇÐL

Попробуйте онлайн!

Использует идею из этого J ответа . Обрежьте до нужной длины каждую итерацию и возьмите точку фиксации. Я подумал, используя S(сумма) вместо Ṁ‘(макс + 1), но я не могу гарантировать его правильность.

фонтанчик для питья
источник
12 байт .
Эрик Outgolfer