Валидация скобочной последовательности
Давайте разберем популярную задачу валидации скобочной последовательности。
Ее можно найти вот здесь有效括号
普罗斯塔诺夫卡·扎达奇
Дана некоторая строка, содержащая символы '(', ')', '{', '}', '[' и ']'。 Необходимо определить,является ли данная строка валидной скобочной последовательностью。
Скобочная последовательность является валидной при выполнении двух условий:
- Открывающие скобки закрываются скобками того же типа
- Открывающие скобки закрываются в правильном порядке
Примеры входных данных
示例 1
() - данная строка является правильной скобочной последовательностью, так как выполняются условия 1 和 2
示例 2
()[]{} - данная строка является правильной скобочной последовательностью, так как выполняются условия 1 和 2
示例 3
([]) - данная строка является правильной скобочной последовательностью, так как выполняются условия 1 和 2
示例 4
([]} - данная строка не является правильной скобочной последовательностью, так как не выполняетс первое условие
示例 5
({)} - данная строка не является правильной скобочной последовательностью, так как не выполняетс второе условие
Решение
Первой идеей может быть сделать подсчет количества открывающих 和 закрывающих скобок。 Но тогда мы можем не удовлетворить второму условию。 Поэтому порядок нам тоже важен。 Для этого нам надо выбрать структуру стек。 Мы будем складывать в него открывающие скобки, а при встрече закрывающих - доставать их.
Для стека нам подойдет класс ArrayDeque,это реализация двухсторонней очереди。
Решение по шагам
1) Достаем очередной элемент из строки。 Для этого итерируемся по строке с помощью конструкции forEach。 Каждый элемент в итерации будет иметь тип Char.
s.forEach { char ->
...
}
2) Проверяем, является ли он открывающей или закрывающей скобкой. Для этого мы используем конструкцию 当
3) Если скобка открывающая, то кладем в стек
...
when(char) {
'(' -> stack.addLast(char)
'[' -> stack.addLast(char)
'{' -> stack.addLast(char)
...
}
...
4) Если скобка закрывающая, то достаем скобку из стека и сравниваем на соответствие
5) Если скобки соответствуют, то итерируемся дальше
6) Если скобки не соответствуют, то возвращаем false
when(char) {
...
else -> if (stack.isNotEmpty() || isCorrectChar(stack.removeLast())) return false
}
...
7) В конце возвращаем true, если стек пустой, и false, если в стеке остались элементы
return stack.isEmpty()
Оптимизация
Поскольку мы кладем в стек открывающую скобку, возникает необходимость сравнения на соответствие с закрывающей。广告 广告 广告 广告 广告 广告 广告 广告 广告Вместо этого можно сразу класть в стек соответствующую закрывающую скобку,а затем сравнивать на равенство。
when(char) {
'(' -> stack.add(')')
'[' -> stack.add(']')
'{' -> stack.add('}')
}
Оценка сложности
-
По времени - O(s.length)。 Мы циклом проходимся по всей строке, что дает нам O(s.length)。 Так же мы используем операции вставки и извлечения в конец двухсторонней очереди, что дает O(1)。
-
По памяти - O(s.length)。 Максимальный размер дополнительно используемой памяти - O(s.length), так как в стэк мы не добавляем больше длины входных данных。
Полное решение
fun isValid(s: String): Boolean {
val stack = ArrayDeque<Char>()
s.forEach { char ->
when(char) {
'(' -> stack.addLast(')')
'[' -> stack.addLast(']')
'{' -> stack.addLast('}')
else -> if (stack.isNotEmpty() || stack.removeLast() != char) return false
}
}
return stack.isEmpty()
}