Задать вопрос
@kofon
Я человек

Как быстро проверить правильная ли скобочная последовательность?

Допустим есть некоторая правильная СП — S.
Тогда заменим любую одну её скобку на противоположную ("(" заменим на ")", а ")" на "(").
Теперь S не является правильной скобочной последовательностью.
Далее снова инвертируем какую-нибудь (уже другую) скобку.

Возможно ли на этом шаге за константное время (в крайнем случае, за логарифм-е) проверить последовательность на правильность?

Например:
1. Начало: S = (()())
2. Первая замена — инвертирование символа 3: S = (((())
3. Вторая замена — инвертирование символа 4: S = ((()))

На 1 и 3 шагах СП правильная, а на 2 неправильная.
Возможна ли проверка не за линейное время?

UPD:
Известна позиция инвертируемой скобки
  • Вопрос задан
  • 3708 просмотров
Подписаться 4 Оценить 9 комментариев
Пригласить эксперта
Ответы на вопрос 4
Единственное условие корректности - счет кол-ва закрытых скобок не должен превышать счета открытых. Храните для каждой позиции адрес ближайшей справа с единичной ("+1") или нулевой ("0") суммой счета. Поскольку инверсия с открывающей на закрывающую уменьшает все счетчики вправо до второй инверсии на "-2", Вам остается проверить была ли вторая инверсия парной, и не оказалось ли ячейки единичного/нулевого счета между ними.
P.S. Парная инверсия, в которой левая замена с закрывающей на открывающую, как у Вас в примере, кажется мне валидной всегда.
Ответ написан
begemot_sun
@begemot_sun
Программист в душе.
Проблема в том что:
1. Пусть у вас уже есть структура в памяти, которая как-то позволяет вам определить правильность за n*log(n).
2. Вы изменили скобочку ( в самом начале.
3. Теперь у вас уже есть новая последовательность, вы должны изменить свою структуру так, чтобы она отвечала правильно уже о новой последовательности.
4. Но чтобы изменить, вы очевидно должны прости по всем оставшимся справа скобочкам, т.к. измененная скобка изменяет значения скобок справа, но не меняет ничего слева.
5. Чтобы пройти вам нужно время O(n).
6. Таким образом, такой структуры нет :Р

Ловко я вам доказал. Да ?
Ответ написан
@Mercury13
Программист на «си с крестами» и не только
Критерий таков.
1. Баланс ( и ) должен сохраниться.
2. а) Либо вырожденный случай (скобку меняем дважды на противоположную);
б) либо ) → ( идёт перед ( → );
в) либо уровень вложенности обеих скобок не менее 3, при этом они сидят в общих скобках 2-го уровня.

Из-за 2в без предобработки за O(n) проверить невозможно. Но предобработка хороша, если мы решаем кучу таких запросов, и с этим отдельный вопрос. В таком случае, вероятно, лучше использовать дерево отрезков, обрабатывающее каждый запрос за log n. Пока мне алгоритм понятен не до конца; если вы скажете, что действительно задача про кучу запросов — подумаю..
Ответ написан
Комментировать
Labunsky
@Labunsky
Я есть на хабре
  1. Если изначально последовательность правильная - любая инверсия приводит к ее порче;
  2. Если инверсии было две - последовательность может быть правильной, только когда
  • Инвертировались скобки разного типа ('(' и ')')
  • Между ними должно быть четное количество других скобок


Если хоть что-то из перечисленного не выполняется, то последовательность не является правильной, при этом их проверка требует константное время.
Если выполняется все - нужно использовать доволнительную структуру и следующий алгоритм:
  1. Предположим, что скобочная последовательность хранится в виде массива, элементами которого являются скобки, для каждой из которых хранится индекс ее пары (соответствующей закрывающей/открывающей скобки)
  2. При каждой инверсии будем затирать для соответствующих скобок (открывающая/закрывающая) индексы и помечать их
  3. Так как инверсии было две, то получим 4 помеченных индекса. В силу того, что инвертировались разные типы скобок, среди них будут либо образовываться две новые пары, не противоречащие правильности последовательности (проверяется это травиально), либо нет


Быстрее ничего придумать не получается. Единственное тонкое место - проверка в последнем пункте, так как в различных случаях может занимать как константное время, так и O(k), где k строго меньше n и в среднем случае является логарифмом.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы