Знайдіть відповідність першої дужки


22

Це було одним із низки викликів, що спричинили день народження Брейн-Флак. Дізнайтеся більше тут .

Виклик

Для цієї задачі вашою метою буде знайти найпершу пару відповідних дужок у повністю збіганій дужці ()[]{}<>дужок. Щоб запозичити визначення DJMcMayhem повністю відповідного рядка:

  • Для цього виклику, «дужка» представляє собою будь-яка з цих символів: ()[]{}<>.

  • Пара дужок вважається «збіганою», якщо дужки, що відкриваються і закриваються, є в правильному порядку і не містять символів всередині них, наприклад

    ()
    []{}
    

    Або якщо кожна субелемент всередині нього також збігається.

    [()()()()]
    {<[]>}
    (()())
    

    Субелементи також можуть вкладатись у кілька шарів глибиною.

    [(){<><>[()]}<>()]
    <[{((()))}]>
    
  • Рядок вважається "Повністю узгодженим", якщо і лише в тому випадку, якщо кожна пара дужок має правильну дужку відкриття та закриття в потрібному порядку.

Вхідні дані

Введення буде складатися з одного непорожнього рядка або масиву char, що містить лише символи ()[]{}<>, і гарантовано буде повністю збігатися. Ви можете приймати дані будь-яким розумним способом, який відповідає нашим замовчуванням вводу / виводу .

Вихідні дані

Виведенням вашої програми або функції буде індекс дужки, який закриває перший. Вихід повинен бути індексованим 0або 1індексованим. Знову ж таки, висновок може бути будь-яким розумним чином, що відповідає нашим за замовчуванням вводу / виводу .

Випробування

Input       0-indexed   1-indexed
()          1           2
(<>)        3           4
<[]{<>}>    7           8
{}{}{}{}    1           2
[[]<>[]]    7           8

Це , найменше виграш байтів!


3
Бонусні бали, якщо ви відповісте на Brain-Flak ofc :)
Ерік Переможник

1
@EriktheOutgolfer Готово
DJMcMayhem

1
Цей прийом дуже корисний для написання неефективних реалізацій BF.
Esolanging Fruit

Відповіді:


2

V , 4 байти

%Dø.

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

Це, на відміну від більшості V відповідей, використовує 0-індексацію. Я надзвичайно пишаюся цією відповіддю, і наскільки далеко зайшла моя мова. Пояснення:

%       " Jump to the first bracket match
 D      " Delete everything under and after the cursor
  ø     " Count the number of times the following regex is matched:
   .    "   Any character

Чи не потрібна котловарка, яка вам потрібна для узгодження <>?
Павло

@Pavel In vim, так. Але не у V.
DJMcMayhem

27

Мозг-Флак , 685, 155, 151 , 137 байт

(())({<{}({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>
([{}()]{})(({})){{}({}[()])(<()>)}{}(<>)<>{{}<>{}({}<>)}{}(<>[]<>)>()}<>)

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

136 байт коду плюс один байт для -a . Один індексований.

530 байтів у гольф! Це, мабуть, найбільший гольф, який я коли-небудь робив.

14 байт збережено завдяки Райлі!

Це зловживає формулою дужок, що відкриваються / закриваються: якщо взяти значення ASCII, збільшити його на одне і взяти модуль 4, відкривачки ( ({[<) завжди отримають 0або 1, тоді як доводчики ()}]> ) завжди отримають 2 або 3.

Пояснення:

#Push 1
(())

#While true
({<

    #Pop stack height
    {}

    #Compute (TOS + 1) % 4
    ({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{})

    #Decrement if positive
    (({})){{}({}[()])(<()>)}{}

    #Push 0 onto alternate
    (<>)

    #Toggle back
    <>

    #Pop two zeros from alternate if closer
    {{}<>{}({}<>)}{}

    #Push height of alternate stack
    (<>[]<>)

#Make each time through evaluate to 1
>()

#Endwhile
}

#Push the number of loops onto the offstack
<>)

8
Для любові до Бога, що на землі це.
Leaky Nun

В основному всі зараз використовують n-1&2/ n+1&2/ -n&2або n%7&2для розрізнення кронштейнів, що відкриваються та закриваються ...
ETHproductions

@ETHproductions Я не впевнений, чи може мозок невдало ефективно обчислити &2, але я вивчу це.
DJMcMayhem

О, я думав, ти. Ви повинні робити щось подібне, щоб розрізняти 0/ 1і 2/ 3... хоча зараз, коли я дивлюся на це, ви просто декрементуєте, якщо позитивно.
Класний

1
(TOS+1)%4Може бути коротше: Спробуйте його в Інтернеті!
MegaTom

11

05AB1E , 17 16 10 байт

-1 завдяки carusocomputing

-6 дякує Аднану за його дивовижне розуміння, що "після збільшення, другий останній біт - 0 для відкриваючої дужки і 1 для закриваючої дужки".

Ç>2&<.pO0k

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

Ç          # Get input as ASCII values
 >         # Increment
  2&       # And with 2 (0 for open and 2 for close brackets)
    <      # decrement 
     .p    # prefixes
       O   # Sum
        0k # Print the index of the first 0

žuтут здається корисним.
Чарівна восьминога урна

žu8ÝÈÏтак, ні, не дуже lol. У кращому випадку все одно це буде 5 байт. Я думав більше розділити на пари брекетів і зняти дужки, поки не залишиться лише одна пара, лічильник приросту на 2 для кожної вилученої пари. Я поняття не маю, якщо це менше. Пробуючи це атм.
Magic Octopus Urn

Для 10 байт: Ç>2&<.pO0k.
Аднан

1
Просто возитися зі значеннями ASCII. Зауважте, що після прирощення другий останній біт призначений 0для відкриваючої дужки та 1для дужки, що закриває.
Аднан

11

Вім, 23 байти

:se mps+=<:>
%DVr<C-a>C1<esc>@"

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

Мені дуже сумно за цю відповідь. Це рішення прекрасно елегантне і коротке, але, за замовчуванням, vim не враховує <і >не відповідає, тому мені потрібно 13 байт кодового коду. Інакше це було б просто 10 байт.

Я б розмістив відповідь V, але це було б лише на один байт коротше, а саме зміна Vrна Ò, оскільки Vrце загальна vim-ідіома.

Це 1-індексований, але може бути тривіально модифікований, щоб бути 0-індексованим, змінивши 1на "a" 0.

:se mps+=<:>        " Stupid boilerplate that tells vim to consider `<` and `>` matched
%                   " Jump to the bracket that matches the bracket under the cursor
 D                  " Delete everything from here to the end of the line
  V                 " Visually select this whole line
   r<C-a>           " Replace each character in this selection with `<C-a>`
                    " This conveniently places the cursor on the first char also
         C          " Delete this whole line into register '"', and enter insert mode
          1<esc>    " Enter a '1' and escape to normal mode
                @"  " Run the text in register '"' as if typed. Since the `<C-a>` command
                    " Will increment the number currently under the cursor


10

Желе , 11 10 9 байт

O’&2’+\i0

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

Пояснення

Ідея тут полягала в тому, щоб знайти «магічну формулу», яка зможе відрізнити відкриття від закриваючих дужок. Я спочатку використовував O%7&2(тобто "взяти код ASCII, модуль 7, порозрядно-і 2"), але запропоновано @ETHproductions O’&2(що замінює модуль 7 декрементом); обидва повертають 0 для одного виду дужок і 2 для іншого. Віднімання 1 ( ) перетворить ці результати на -1 та 1.

Решта коду є +\. +\виробляє кумулятивну суму. Якщо набір дужок правильно підібраний, він буде містити однакову кількість -1s і 1s, тобто його сукупна сума буде дорівнює 0. Тоді нам просто потрібно повернути індекс першого 0 в результуючому списку; ми можемо це зробити з i0.


Захоплююче, як ми застосували подібний підхід до виявлення дужок, що закриваються. На жаль, я знайшов лише нижчу версію:b*2%7>3
2501

Цікавий підхід! Я розробив довший відповідь (на практику), який, врешті-решт, перейшов нанівець практично до цього, за винятком цікавого, замість першого декременту на вашій посаді, натомість у мене був приріст. :)
HyperNeutrino

9

Сітківка , 26 24 байти

M!`^.(?<-1>([[({<])*.)*

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

Результат на основі 1.

Пояснення

Дуже інше рішення Retina, яке по суті базується на одному (і дуже читабельному ...) регулярному вираженні. Для цього використовується нова методика, яку я виявив вчора для відповідності врівноважених рядків з використанням балансуючих груп .

M!`^.(?<-1>([[({<])*.)*

Знайти ( M) та повернути ( !) всі збіги регулярного вираження ^.(?<-1>([[({<])*.)*. Цей регекс пропускає перший символ рядка, а потім використовує балансуючі групи для відстеження глибини введення. Будь-яке [({<збільшення глибини (відслідковується за групою 1) та будь-який інший символ зменшує глибину (в принципі, .дозволяє зменшити глибину, відкриваючи дужки, але оскільки регекс жадібно узгоджується, ретранслятор ніколи не намагатиметься цього ). Дивна хитрість полягає в тому, що (?<-1>...)укладена група 1працює, тому що спливання з балансуючої групи відбувається в кінці групи. Це економить два байти на стандартному підході у формі((open)|(?<-2>close))*. Збіг обов'язково зупиняється на дужці, яка закриває першу, тому що ми пропустили її, тому вона не враховується в глибині стека (і глибина стека не може бути негативною).

Тривалість цього матчу - це індекс на основі дужки, який ми шукаємо.


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


Це геніально!
Павло

Коротший підхід : видаліть другу частину рядка замість того, щоб відповідати першій частині. Мені подобається, як ти вимірював довжину струни, btw!
Лев

@Leo Це дійсно акуратно! Ви можете опублікувати це як окрему відповідь :)
Мартін Ендер

Гаразд, цей новий трюк для збалансованих струн чудовий: D
Лев

6

Сітківка , 24 байти

.(([[({<])|(?<-2>.))*$


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

Це натхнене рішенням Мартіна Ендера .

Пояснення

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

Наступний рядок порожній, тому ми заміняємо відповідність порожнім рядком, тобто тепер нам потрібно лише порахувати решта символів, щоб отримати (0-індексований) бажаний результат.

Останній порожній рядок підраховує кількість збігів порожнього рядка в рядку, що на одну кількість більше символів у рядку, еквівалентну 1-індексованому результату.


Я знайшов новий метод узгодження збалансованих рядків , які вчора зберігає два байта на обидва наших відповіді: tio.run / ## K0otycxL / K @ q4Z7wX0 / D3kbX0E4jOlqj2iZWU0tPU0uFi @ v / ... (і , можливо , десяток інших з них я написав в минулий ...)
Мартін Ендер

5

Perl 5 , 28 байт

Збережені 6 байт, використовуючи тільки .замість [>})\]], від Мартіна Ендер Retina відповіді .

27 байт коду + -pпрапор.

/([<{([](?0)*.)+?/;$_=$+[0]

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

Рекурсивний регекс, яке гарне винахід.
Регекс шукає дужку, що відкривається ( [<{([]), за нею йде рекурсивний виклик ( ?0), а потім закривається дужка ( .). Все це не жадібно ( +?), тому воно відповідає якомога коротше від початку. Індекс кінця матчу - відповідь, і як це відбувається, його можна знайти в $+[0].


4

JavaScript (ES6), 55 53 52 байти

Збережено 1 байт завдяки @Adnan

f=([c,...s],i=1)=>(i-=-c.charCodeAt()&2)&&1+f(s,++i)

Для кожного відкриваючого кронштейна прийняття його char-коду mod 4 дає 0 або 3; для дужок, що закриваються, це дає нам 1 або 2. Отже, ми можемо розрізнити дужки, що відкриваються і закриваються, відкидаючи char-код дужки (який перевертає біти і віднімає 1) і беремо другий найменш значущий біт; тобто n&2.


Я думаю, що замість n-1&2, -n&2також працює?
Аднан

@Adnan Хм, я думаю, ти маєш рацію. Спасибі!
ETHproductions

4

С, 75 72 56 55 54 45 байт

a;f(char*s){return(a-=(-*s++&2)-1)?1+f(s):0;}

Побачити це працює в Інтернеті .

Якщо ви хочете, щоб результат був 1-індексованим замість 0-індексованого, замініть останній 0на 1.


4

Python 2.7 + Numpy, 85 79 байт

Моя перша спроба кодового гольфу:

from numpy import*
lambda s:list(cumsum([(ord(x)+1&2)-1for x in s])).index(0)

1
Ласкаво просимо на сайт!
DJMcMayhem

1
Вам не потрібно називати лямбда, ви можете видалити g =
Павло

4

Brain-Flak , 97 байт (96 для коду, 1 для прапора)

{}<>(())({<(<()>)<>({<({}[()])><>([{}]())<>}{})<>(<{}>())<>{({}[()])<>([{}])<>}{}<>({}{})>()}{})

Біжи з -aпрапором.

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

Пояснення:

#Skip the first open bracket 
{}

#Place a 1 on stack B, representing the nesting depth
<>(())

#Start a loop, until the depth is 0
({<

 #Divide the ASCII code by 2, rounding up
 (<()>)<>({<({}[()])><>([{}]())<>}{})<>

 #Replace TOS B with a 1
 (<{}>())

 #Swap back to stack A
 <>

 #Negate the 1 on stack B n times (n = ASCII value+1/2)
 {({}[()])<>([{}])<>}{}

 #Swap back to stack B
 <>

 #Add the 1/-1 (depending on Open/close bracket) to the nesting depth accumulator
 ({}{})

 #Count loop cycles
 >()

#end loop, print result implicitly by pushing to the stack 
}{}) 

Це просто працює, добре.


3

Сітківка , 34 байти

^.
!
T`([{}])`<<<>
+T`p`!`<!*>
\G!

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

Результат базується на 0.

Пояснення

^.
!

Замініть перший символ символом a !. Це призводить до того, що дужка, яку ми шукаємо, не має собі рівних.

T`([{}])`<<<>

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

+T`p`!`<!*>

Багаторазово ( +) замінити кожен символ у всіх матчах <!*>з !с. Тобто ми узгоджуємо пари дужок, які не містять подальших необроблених дужок, і перетворюємо їх на подальші знаки оклику. Це перетворить увесь рядок, крім незрівнянної дужки закриття, у знак оклику.

\G!

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


Я бачив, що ви відповіли на домашній сторінці і знав, що буде використовувати якийсь регулярний вираз
Крістофер

@Christopher Eh, цей ледве використовує будь-який регулярний вираз (на відміну від іншого відповіді на Retina, який я щойно опублікував ...).
Мартін Ендер

Шиш. Регекс багато?
Крістофер

Чому не це працює?
Leaky Nun

@LeakyNun Тому що (?!(2))просто (?!2). Ви , ймовірно , мав в виду (?(2)(?!))або (?2)!). Ви також забули врятуватися від а, ]і остаточне +потрібно *.
Мартін Ендер

2

PHP, 116 байт

for($l=["("=>")","["=>"]","{"=>"}","<"=>">"][$f=$argn[0]];;$d>0?$i++:die("$i"))$d+=$f!=($n=$argn[$i])?$n==$l?-1:0:1;

Інтернет-версія


Чи не потрібно PHP починати <?php?
Павло

@Phoenix: Є окремий інтерпретатор PHP, який не вимагає початкового тегу. Ось що зазвичай використовується для гольфу.

@ ais523 У цьому випадку PHP працює з командного рядка з опцією -R
Jörg Hülsermann

2

Пітон , 76 байт

f=lambda s,r=[],i=0:(i<1or sum(r))and f(s[1:],r+[(ord(s[0])+1&2)-1],i+1)or i

Рекурсивна функція, яка використовує порядковий другий LSB як прапор для відкритого проти закритого трюку, який використовується багатьма знайденими Аднаном (і, ймовірно, іншими). Хвіст вражає, коли сукупна сума -1для відкритих і 1для близьких досягає нуля. Індекс зберігається в змінній, оскільки він на байт дешевший, ніж використання len(r), індексація базується на 1.

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


2

Ruby, 35 34 байт

p$_[/[<{(\[](\g<0>)*[>})\]]/].size

На основі відповіді Дади Perl5 . Вихід 1-індексований. Потрібен виклик інтерпретатора Ruby з -nопцією (неявна while getsпетля).

Редагувати: це також 35 34 байти, але це ще одна можлива відправна точка для подальшого зменшення цієї відповіді.

p$_[/[<{(\[](\g<0>)*[>})\]]/]=~/$/

Edit2: видалено зайві пробіли після p.

Edit3: ще пару 34-байтних відповідей.

~/[<{(\[](\g<0>)*[>})\]]/;p$&.size
p~/[<{(\[](\g<0>)*[>})\]]/+$&.size

2
Ласкаво просимо до PPCG!
Павло

1
Цінується! :)
Рей Хамель


1

Пакетна, 172 байти

@set/ps=
@set/ai=d=0
:l
@set/ai+=1,d-=1
@set c="%s:~,1%"
@set "s=%s:~1%
@for %%a in ("<" "(" "[" "{")do @if %%a==%c% set/ad+=2&goto l
@if %d% gtr 0 goto l
@echo %i%

1-індексований. <>s, звичайно, спеціальні символи в Batch, тому не тільки мені доведеться цитувати все, але я навіть не можу робити хитрощів, таких як зробити їх gotoмітками.


1

R, 126 байт

s=readline();i=0;r=0;for(c in strsplit(s,"")[[1]]){if(grepl("[\\[\\(\\{<]",c))i=i+1 else i=i-1;if(i==0){print(r);break};r=r+1}

0

C, 127 байт

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

c(x){x-40&x-60&x-91&x-123?-1:1;}
f(i,t)char*t;{return i?f(i+c(*t),t+1):t;}
s(char*t){return f(c(*t),t+1)-t;}

Вихідні дані

2   ()
4   (<>)
8   <[]{<>}>
2   {}{}{}{}
8   [[]<>[]]

Будь-який коментар, зворотний зв'язок.
Khaled.K

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