JavaScript (ES7), 121 117 байт
x=>(a=b=0,[for(c of x)for(d of'1234')(e=c.charCodeAt()/26|0)==d?a^=1<<d:b^=(a>>d&1)<<d*4+e],f=y=>y&&y%2+f(y>>1))(b)/2
Вау. Это было весело. Я набросал идею ответа, когда впервые появился этот вызов, но его длина превышала 150 байтов, и я не хотел прикладывать усилия для его игры в гольф. Вчера я наткнулся на эту идею в своей записной книжке и решил, что не перестану думать об этом, пока полностью не поиграю в нее. В итоге я написал два совершенно новых алгоритма, первый из которых оказался на несколько байт короче, после того, как вы проиграли около 25 байт с кучей хитов.
Как это работает
Сначала мы устанавливаем переменные a
и b
в 0
. a
является 4-битным двоичным массивом пар скобок, в котором мы сейчас находимся, и b
16-разрядным двоичным массивом пар скобок, которые связаны вместе.
Далее мы перебираем каждый символ c
в x
и каждый символ d
в '0123'
. Сначала мы определяем , какой тип кронштейна c
находится с e=c.charCodeAt()/26-1|0
. Десятичные коды символов каждого типа скобок:
() => 40,41
<> => 60,62
[] => 91,93
{} => 123,125
Делив на 26, вычитая 1 и настил, мы сопоставляем их с 0, 1, 2 и 3 соответственно.
Далее мы проверяем, равно ли это число текущему значению d
. Если это так, мы либо входим, либо выходим из d
типа th скобки, поэтому мы переключаем d
бит th a
с помощью a^=1<<d
. Если это не так, но мы находимся внутри d
скобки, нам нужно перевернуть e
бит в d
4-битной секции b
. Это делается так:
b^=(a>>d&1)<<d*4+e
(a>>d&1)
Возвращает d
бит в a
. Если мы находимся внутри d
скобочного типа, это возвращает 1; в противном случае возвращается 0. Затем мы сдвигаем это влево на d*4+e
биты, а XOR b
- на результат. Если мы находимся внутри d
скобочного типа, то это XOR d*4+e
бит b
; в противном случае это ничего не делает.
В конце всего цикла b
будет содержаться число 1-бит, равное удвоенному желаемому возвращаемому значению. Но нам все еще нужно выяснить, сколько это битов. Вот где f
входит подфункция:
f=y=>y&&y%2+f(y>>1)
Если y
0, это просто возвращает 0. В противном случае, он принимает последний бит y
с y%2
, а затем добавляет результат y
повторного выполнения всех функций, кроме последнего, через функцию. Например:
f(y) => y && y%2 + f(y>>1)
f(0b1001101) => 1 + f(0b100110) = 4
f(0b100110) => 0 + f(0b10011) = 3
f(0b10011) => 1 + f(0b1001) = 3
f(0b1001) => 1 + f(0b100) = 2
f(0b100) => 0 + f(0b10) = 1
f(0b10) => 0 + f(0b1) = 1
f(0b1) => 1 + f(0b0) = 1
f(0b0) => 0 = 0
Мы пробегаем b
эту функцию и делим результат на 2, и наш ответ есть.