Понеділок міні-гольф №1: Зворотний вирішальник Фібоначчі


28

Понеділок Міні-Гольф: Серія коротких викликів з , що публікуються (сподіваємось!) Кожного понеділка.

Фібоначчі-подібні послідовності отримують , використовуючи той же спосіб, відомої послідовності Фібоначчі ; тобто кожне число F (n) знаходимо шляхом додавання попередніх двох чисел у послідовності ( F (n) = F (n-1) + F (n-2) ) або відніманням наступних двох чисел ( F (n) = F (n + 2) - F (n + 1) ). Основна відмінність полягає в тому, що ці послідовності можуть починатися з будь-яких двох чисел. Нульова індексація цих послідовностей є спірною, але наразі ми будемо використовувати це правило:

  • 0 число в послідовності, подібної до Фібоначчі, - це останнє число, яке менше попереднього числа.

Як приклад, послідовність Фібоначчі може бути записана як 1, 0, 1, 1, 2, 3, 5..., тому 0 число в послідовності є одиноким 0.

Виклик

Мета завдання - написати програму або функцію, яка бере три цілі числа, у будь-якому форматі:

  • А і В , два числа, з яких можна почати генерувати послідовність.
  • N - довжина отриманої послідовності для виведення.

І виводить перші N числа послідовності, починаючи з 0-го.

Деталі

  • A , B і N можуть прийматися в будь-якому порядку та форматі, якщо вони видимо розділені. Якщо ви використовуєте інше замовлення / формат, вкажіть, що це таке.
  • Ви можете припустити, що A , B і N завжди є натуральними числами.
  • Можна припустити, що N не більше 100, а отримана послідовність не буде містити x >= 2^31.
  • Якщо A більший за B , то B - 0 число в послідовності.
  • Вихідні дані повинні бути розділені пробілами, комами та / або новими рядками.
  • Доступний пробіл або новий рядок, але не кома.

Тестові кейси

Приклад 1:

8 13 10

Працюючи назад, 8 13поки не знайдемо число, більше, ніж попереднє, ми отримаємо 13 8 5 3 2 1 1 0 1. Таким чином, 0є 0 числом у цій послідовності. Просуваючись до цього, ми роздруковуємо 0та наступних 9 членів:

0 1 1 2 3 5 8 13 21 34

Приклад 2:

23 37 5

Знову працюючи назад, щоб знайти 0 число, ми знаходимо 37 23 14 9 5 4 1 3. Цього разу номер 0 1, тому ми роздруковуємо його разом з наступними 4 членами:

1 4 5 9 14

Приклад 3:

4 3 8

З цим нам не потрібно працювати назад, щоб знайти 0 число, оскільки 3воно менше 4:

3 7 10 17 27 44 71 115

Приклад 4:

29 47 11

Результат:

1 3 4 7 11 18 29 47 76 123 199

Оцінка балів

Це , тому найкоротший дійсний код у байтах виграє. Tiebreaker переходить до раніше опублікованих подань. Переможець буде обраний наступного понеділка, 28 вересня. Удачі!

Редагувати: Вітаю переможця @Jakube, використовуючи Pyth за дивовижні 23 байти!


10
Я видалив створений вами тег [понеділок-міні-гольф]. Я не думаю, що ми повинні створювати теги для більш-менш довільних груп проблем. Тег насправді нічого не говорить вам про виклик, і якщо ви хочете знайти все це, можна просто пошукати фразу на панелі пошуку. Крім того, якщо ви включите посилання на цей перший виклик у кожній наступній партії, усі вони будуть пов’язані у розділі "Пов'язані питання" на бічній панелі.
Мартін Ендер

@ MartinBüttner Добре, спасибі; Я буду пам'ятати про це.
ETHproductions

Чи можу я сприйняти вхід, як я цього хочу (список буквальних пітонів [8, 13, 10])?
Блакитний

3
Наразі завдання викликає написання програми . Чи означає це, що функції заборонені? (CC @LuisMendo)
Денніс

3
@Dennis Вибачте, ковзнув мені розум. Функції також дозволені. Дякуємо, що вказали на це!
ETHproductions

Відповіді:


12

Pyth, 23 байти

AQWgHGA,-HGG)VvwHA,H+GH

Спробуйте в Інтернеті: Демонстрація або Тестовий набір

Досить незвичний стиль програмування Pyth. Іноді функціональне програмування має свої недоліки.

Пояснення:

AQWgHGA,-HGG)VvwHA,H+GH  Q = input list of the two starting numbers
AQ                       G, H = Q (unpacking Q)
  WgHG                   while H >= G:
      A,-HGG                G, H = [H - G, G]
            )            end while
              vw         read a number from input
             V           for N in range(^):
                H           print H
                 A,H+GH     G, H = [H, G + H]

12

Сітківка , 65 54 байти

+`(1*),\1(1*)
$2,$1
+`(1*)(,1*);1\B
$1$2$2$1;
^1*,|;1
<empty>

Тут <empty>представлений порожній проміжний рядок. Запустити код як єдиний файл із -sпрапором.

Формат введення є

A,B;N

де цифри представлені одинаково . Вихід - це розділений комою список, також в одинаковому. Наприклад:

8 13 10

був би

11111111,1111111111111;1111111111

і врожайність

,1,1,11,111,11111,11111111,1111111111111,111111111111111111111,1111111111111111111111111111111111

Пояснення

+`(1*),\1(1*)
$2,$1

Спочатку зводимо Aі Bдо 0-го і -1-го елемента. +Каже Retina , щоб повторювати це регулярний вираз заміни до тих пір , або регулярний вираз не припиняє узгодження або заміна не змінює рядок. Регулярний вираз захоплює Aв групі 1 з (1*), а потім переконується , що B, по крайнього заходу так само великим , як Aпри захопленні B-Aз \1(1*)в групі 2. Це гарантує , що цей цикл завершується один раз A>B.

Заміна просто перетворюється A,Bна B-A,Aвстановлення матчу на $2,$1.

+`(1*)(,1*);1\B
$1$2$2$1;

Тепер ми вже отримали перший номер необхідного виводу в рядку (як і той, що передує його, який нам потрібно буде позбутися пізніше). Ця заміна тепер додає ще одне число як суму останніх двох чисел під час прийому 1з N. Оскільки у нас вже є одне число, ми хочемо, щоб це сталося лише N-1. Ми робимо це, гарантуючи, \Bщо ;11в кінці рядка ще є принаймні . Якщо ми називаємо два останніх значення послідовності Cі D, то регулярний вираз охоплює Cгрупу 1 та ,Dдругу групу. Ми пишемо їх назад $1$2. Тоді також пишемо, $2$1що означає ,D+C. Зауважте, що ми не записуємо назад синглу, в якому 1ми відповідалиN, тим самим декрементуючи його.

^1*,|;1
<empty>

Нарешті, ми повинні позбутися від -1st елемента послідовності, а решта ;1від N, яку ми просто шляхом зіставлення або з тих , і замінити його з нового рядка.


7

Python 2, 93 87 67 61 60 байт

i,j,l=input()
while j/i:i,j=j-i,i
exec"i,j=j,i+j;print i;"*l

Отримує введення (як буквальний список пітонів [8,10,13])

Опрацьовує 0-й термін

Потім друкується послідовність доповнень до досягнення довжини


1
Хороший метод. Для циклу без індексу for _ in[1]*l:це зробити трохи коротшеexec"stuff;"*l
xnor

@xnor: Мені це здається значно довше.
рекурсивна

Порівняйте for _ in[1]*l:stuffз exec"stuff;"*l. @xnor не помістив частину матеріалу в цикл for. Або for _ in[1]*l:доexec";"*l
Блакитний

2
Ви можете замінити j>=iна j/i. Щойно це з’ясували! (Тому що ви можете припустити, що A, B і N завжди є цілими цілими числами )
mbomb007,

6

CJam, 26 23 байт

Завдяки Деннісу за збереження 3-х байт.

q~{_@\-_g)}g\@{_@+_p}*t

Вводить порядок N B A(розділений пробілом будь-якого типу). Виводить результат у вигляді списку, розділеного новим рядком, і закінчується помилкою .

Перевірте це тут.

Пояснення

Це йде на крок далі при знаходженні 0-го елемента. Тобто він припиняється, як тільки одне із значень є негативним.

q~      e# Read and evaluate input, pushing N, B and A on the stack.
{       e# do while...
  _@\-  e#   B, A = A, B-A
  _W>   e#   Check if A is still non-negative.
}g
\@      e# Reorder N B A into A B N.
{       e# Run the following N times...
  _@+   e#   A, B = B, A+B
  _p    e#   Print B.
}*
t       e# The last A, B are still on the stack. We remove them by trying to
        e# execute a ternary operator: it pops the first two values but then
        e# terminates the program with an error, because there is no third value.

q~{_@\-_g)}g\@{_@+_p}*t( N B A) зберігає три байти.
Денніс

Хоча я сам намагався вирішити це в CJam, у мене виникли проблеми із введенням прикладу 1. Тепер я бачу, що і це рішення не дає очікуваного результату. Де тут вада? Я думаю, що замість того B>A, щоб перевірити, B not smaller than Aчи потрібно щось перевірити , але я не можу зрозуміти, як це зробити в CJam. EDIT: Рішення Денніса друкує правильний вихід.
Cabbie407

Ну, я це вирішив у своєму рішенні.
Cabbie407

@ Cabbie407 Ти маєш рацію, я повинен був використовувати <!замість цього >.
Мартін Ендер

Ага, гаразд. Мені було цікаво, куди це поставити !. Я просто додав один, щоб він працював;)
Cabbie407

5

Лабіринт , 58 54 49 46 44 байт

Спасибі Sp3000 за те, що він запропонував використовувати побітне заперечення, що зберегло два байти.

??#"{=
  ;  -
@"~~:}
~""
?
"}}:=
(   +
{{\!:

Формат вводу є B A N. Вихід - це список, відокремлений новим рядком.

Пояснення

(Трохи застаріла. Основна ідея все одно та сама, але макет коду зараз інший.)

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

Для цього використовується пара чудових прийомів з гольфу в Лабіринті. Перегляньмо код у розділах:

?"
}

IP починається ?справа (що читається A). На "(не-оп) він потрапляє в глухий кут, тому обертається, ?знову виконуючи (читаючи B). Нарешті, }переходить Bна допоміжний стек. Тупик економить байт над наївним

?
?
}

Тепер цикл, який знаходить початок послідовності:

)(:{
"  -
" "`?...
=}""

)((Приріст декремент) є не-оп, але це необхідно для того, щоб верхня частина стека позитивна на стику (наприклад , що IP повертає на схід). :дублікати A, {рухається Bназад до головного стека, -обчислюють A-B. Те, що ми насправді хочемо, це, B-Aоднак, так і `заперечує значення.

Зараз це чотиристоронній перехід. Для отримання негативних результатів, ІР робить поворот ліворуч у напрямку ?, читаючи Nта переходячи до наступної частини програми. Якщо результат дорівнює нулю, IP продовжує рухатися на південь, робить поворот у кутку та залишається у циклі. Якщо результат позитивний, ІР приймає поворот праворуч (на захід), повертає в кут і робить інший поворот праворуч (знову захід), щоб він також залишався в циклі. Я думаю, що це може стати загальною схемою, щоб відрізняти негативні від негативні (або позитивні від непозитивні) значення:

                v
                "
               """>negative
non-negative <"""

Принаймні, я ще не зміг знайти більш компактний / корисний макет для цього випадку.

У будь-якому випадку, поки Aце негатив, цикл продовжується, }переміщується Aдо допоміжного стека та =підміняється Aта B.

Після того, Aяк негативний, ?читається, Nі ми переходимо до другого циклу:

 }:=+:
 }   !
?"({{\

Ми знаємо, що Nце позитивно, тому ми можемо розраховувати на ІР, повернувши ліворуч (на північ). Тіло циклу тепер просто:

}}:=+:!\{{(

На словах: рухається як Nі Aна допоміжний стек. Скопіюйте B, замініть копію Aі додайте Aдо іншої копії B. Скопіюйте його ще раз, щоб надрукувати поточне значення B. Друк нового рядка. Переміщення Bта Nповернення до основної стеки та декременту N.

Хоча Nце позитивно, IP буде приймати правий поворот (на північ), продовжуючи цикл. Як тільки Nдосягне нуля, код припиняється досить вигадливим чином:

IP продовжує рухатися прямо вперед (на захід). В ?намагається прочитати інше ціле число, але ми вже досягли EOF, так що на насправді штовхає 0замість цього. `намагається заперечити це, але це все одно дорівнює нулю. Таким чином, IP все ще рухається на захід, повертає поворот у кутку, а потім продовжує рухатися вниз на той, @який припиняє програму.

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


5

C, 105 102 100 байт

main(a,b,n,t){for(scanf("%d%d%d",&a,&b,&n);t=b-a,t>=0;a=t)b=a;for(;n--;b=t)t=a+b,printf("%d ",a=b);}

Дякуємо @ C0deH4cker за те, що виграли 2 байти!

Спробуйте в Інтернеті на Ideone .


4

Матлаб / Октава, 115 125 байт

function x=f(x,n)
while x(2)>=x(1)
x=[abs(x(1)-x(2)) x];end
x=x([2 1]);for k=1:n-1
x=[x(1)+x(2) x];end
x=x(n:-1:1);

Функцію слід називати як f([8 13],10).

Приклад (Matlab):

>> f([8 13],10)
ans =
     0     1     1     2     3     5     8    13    21    34

Або спробуйте в Інтернеті (Octave) .


Відповідно до правил, ви можете змінювати вхід, тому f([a b],n)слід дозволити.
стакан

@beaker Дякую! Я збирався це зробити ... але тоді я прочитав правило "Введення та вихід можуть бути розділені пробілами, комами чи новинками" і заплутався.
Попрошу

Так, я не знаю, чи x=f(x,n)зараховується заголовок функції ...
beaker

@AlexA. Я відповідав на коментар Луїса щодо правила "Введення та вихід можуть бути розділені пробілами, комами чи новими рядками", а "A, B і N" ОП можуть прийматися в будь-якому порядку та форматі, якщо вони є видимо розлучені ». Оскільки A і B більше не помітно відокремлюються у заголовку функції, я запитував, чи допустимо мати лише два аргументи функції.
стакан

3

Haskell, 67 65 56 байт

a#b|a>b=b:scanl(+)(a+b)(a#b)|1>0=(b-a)#a
n%a=take n.(a#)

Дякуємо @nimi для пропозицій

Це визначає потрійну функцію інфіксації %, яка викликається у форматі (n%a)b, наприклад:

> (10%8)13
[0,1,1,2,3,5,8,13,21,34]

Пояснення

Бінарна функція інфіксне #, певна на першій лінії, приймає два цілих числа aі bповертає нескінченної Фібоначчі-подібні послідовності , де aі bвідбуваються в наступних друг за другом елементів.

a#b                                       -- Define a#b:
   |a>b=                                  -- if a>b, then a#b is
        b:                                -- the sequence that starts with b and
          scanl(+)     (a#b)              -- continues with the sums of prefixes of a#b
                  (a+b)                   -- plus the additional term a+b;
                            |1>0=(b-a)#a  -- otherwise, it's (b-a)#a.

Функція %просто приймає перші nелементи a#b.


Ви можете створити послідовність поля з let f=a:scanl(+)(a+b)f in f(-> full #: a#b|a>b=let f=a:scanl(+)(a+b)f in f|1>0=(b-a)#aі зберегти два байти.
nimi

@nimi Спасибі; Я побіг із вашою ідеєю і врятував загалом 9 байт.
Згарб

3

> <>, 33 31 + 1 для -v = 32 байти

&:{:@(?v:}-$&
-1;!?:&<$+{oan::$&

Введення потрібно натиснути на стек, використовуючи -v, оскільки розбір десяткових чисел нетривіальний у> <>.

Пояснення:

Я представлятимуть стек після кожної (групи) операцій. Починається з [F (n), F (n + 1), N]

Перші рядки спускаються на серію до 0-го терміну:

& removes N from the stack to put it into a register. [F(n), F(n+1)]
:{:@ move the stack and duplicate items to get [F(n+1), F(n), F(n+1), F(n)]
(?v compares the two top items of the stack and branch to the second line if F(n+1) < F(n) [F(n+1), F(n)]
:} move the stack and duplicate its top to get [F(n), F(n+1), F(n)]
- substracts the two top items and put the result on top of the stack [F(n), F(n+1) - F(n)]
$ switchs the top two values of the stack. [F(n+1) - F(n), F(n)]
& retrieve the value from the register. iteration complete, since [F(n+1) - F(n), F(n), N] can also be read as [F(n-1), F(n), N]

Другий рядок йде вгору по серії, поки не надрукується N термінів:

< changes the code pointer direction to the left [F(0), F(-1)]
& retrieves the stored value back from the stack [F(0), F(-1), N]
:?!; copies N to compare it to 0, stops if it is [F(0), F(-1), N]
1- decreases it [F(0), F(-1), N-1]
& stores it back [F(0), F(-1)]
$:: makes the stack [F(-1), F(0), F(0), F(0)]
n{ prints the top of the stack then left shifts it [F(0), F(0), F(-1)]
ao displays a line feed (ascii character 0x0a) [F(0), F(0), F(-1)]
+ adds the two top values [F(0), F(-1) + F(0)]
$ switch the two top values. iteration complete since [F(-1) + F(0), F(0)] which can be read as [F(1), F(0)]

Ви повинні мати можливість зменшити кількість байтів на 2, змінивши 00.в першому рядку на &. Теоретично, !слід працювати, але я думаю, що> <> прокладки шириною ліній відповідають ширині найдовшої (правка: саме тому я думаю, що у вас 00.в першу чергу).
коул

Так, я не надто впевнений у цьому, я бачив, як люди тут використовують! У такий спосіб, що проігнорував пробіли. Я знаю, що онлайн-перекладач на fishlanguage.com не працює таким чином, але, можливо, інтерпретатор пітона. & трюк чудово все одно, дякую!
Аарон

Онлайн-перекладач працює з !або ?(в кінці рядка), якщо він знаходиться на найдовшій лінії. Ви можете спробувати щось на кшталт, 1n!і воно помилиться, але якщо під ним є рядок із чимось довшим, ніж, наприклад lorumipsum, не вийде.
Коул

"Вихідні дані повинні бути розділені пробілами, комами та / або новими рядками." Вибачте, але вам доведеться використовувати іншу версію. Хороша робота, хоча!
ETHproductions

Виправлено це, я використовував \ n замість пробілів, щоб зберегти 2 байти
Аарон,

2

Java, 113 78 76 байт

Кредит припадає на ETHproduction за надання алгоритму, який я використовую у цій відповіді.

(a,b,n)->{for(;a<=b;b-=a)a=b-a;for(;n-->0;b+=a,a=b-a)System.out.println(b);}

Спробуйте тут .

Пояснення:

(a,b,n)->{
    for (;a<=b;b=b-a)a=b-a;  //Compute previous terms while a <= b
    for (;n-->0;b=a+b,a=b-a) //Compute and print next terms while n > 0
    System.out.println(b);   //Print term
}

Оригінальний підхід, 113 93 байт

Виглядає більш гофровано;)

String a(int a,int b,int n){return n<0?a+" "+a(b,a+b,n+1):n>0?a>b?a(b,a+b,-n):a(b-a,a,n):"";}

Спробуйте це тут .

Пояснення:

String a(int a, int b, int n){
    return 
    n < 0 ?                           //If n < 0
        a + " " + a(b, a + b, n + 1)  //Return a + next terms and increment n.
    :                                 //Else
        n > 0 ?                       //If n > 0
            a > b ?                   //If a > b
                a(b, a + b, -n)       //Negate n and return terms.
            :                         //If a <= b
                a(b - a, a, n)        //Generate previous term.
        :                             //If n == 0
            ""                        //Return nothing.
    ;
}

3
Що? Java коротша за JS?!?
Повинно

@ETHproductions я фактично скопіював ваш алгоритм (а потім переграв його): P
TheNumberOne

Це добре зі мною, я взяв деякі ваші вдосконалення;) Я забув друкувати кожен елемент окремо, був дійсним у JS.
ETHproductions

Ви можете скоротити b=b-aдо b-=a, і те ж саме з a=b+a. Це заощадить 2 байти
Хав'єр Діас

+1 - зробити так багатослівним подання мови. Зазвичай подання Java є найдовшими!
DankMemes

2

Javascript (ES6), 83 73 63 байт

Це може бути гольф до максимуму. Ми побачимо.

(a,b,n)=>{while(a<=b)b-=a=b-a;for(;n--;console.log(a=b-a))b+=a}

Безголівки:

function f(a,b,n) {
  // repeat until we find the 0th item...
  while (a <= b) {  // if a = 5, b = 8:
    a = b - a;      // a = (8 - 5) = 3
    b = b - a;      // b = (8 - 3) = 5
  }
  // repeat n times...
  while (n-- > 0) { // if a = 5, b = 8:
    b += a;         // b = (8 + 5) = 13
    a = b - a;      // a = (13 - 5) = 8
    console.log(a); // print out each item
  }
}

1

Mathematica 112

Зрештою буде гольф

z[a_, b_, n_] := (
  f[0] := Min[a, b];
  f[1] := Max[a, b];
  f[x_] := f[x - 1] + f[x - 2];
  f /@ Range[n]
  )

1

CJam, 40 байт

l~:A;{_@_@)<}{_@\-\}w\{A(:A0>}{_p_@+}w\;

Кроки дитини. Це моя перша програма CJam коли-небудь, тому я пишаюся, що вона працює взагалі.

Він приймає дані в тій же формі, що і в прикладах.

Зараз я бачив, що міг зменшити його до 33 байт за допомогою { ... }*конструкції.

l~:A;{_@_@)<}{_@-z\}w\A{_p_@+}*;;

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


1

Рубін, 141 байт

def u a,b,n,z=""
n<1 ? z.chop : u(b,a+b,n-1,z+"#{a} ")
end 
def d a,b,z=0
a.abs>b ? z : d(b-a,a,[a,b]) 
end 
def f a,b,n
x,y=d a,b 
u x,y,n
end 

Виконання

Функція f створює потрібний вихід, імена аргументів відповідають назвам змінних з питання

f(8,13,10) # returns => "0 1 1 2 3 5 8 13 21 34"

Нічого розумного:

  • u ( вгору ) функція обчислює n елементів у послідовності поля, починаючи з a, b, використовуючи рекурсію
  • d ( вниз ) функція знаходить 0-й і 1-й елемент, задані двома кінцевими елементами за допомогою рекурсії
  • Функція f ( Florida ) об'єднує їх два разом


0

Рубі, 81 75 73

a,b,n=23,37,5;while(c=b-a)<a;b,a=a,c;end;p a;[*2..n].map{b=c+a;c,a=a,b;p b}

Скорочено на 6 байт при заміні for-loop на range.map

a,b,n=23,37,5;while(c=b-a)<a;b,a=a,c;end;p a;[*2..n].map{p b=c+a;c,a=a,b}

Збережено ще 2 байти переміщенням оператора print




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