Алгоритм: проходим по строке. Открывающую скобку кладём в стек. При закрывающей — снимаем с вершины и проверяем парность.
def is_balanced(s: str) -> bool:
pairs = {")": "(", "]": "[", "}": "{"}
stack: list[str] = []
for ch in s:
if ch in "([{":
stack.append(ch)
elif ch in ")]}":
if not stack or stack.pop() != pairs[ch]:
return False
return not stack # стек должен опустеть
print(is_balanced("([{}])")) # True
print(is_balanced("(]")) # False
print(is_balanced("((()))")) # True
print(is_balanced("(()")) # False — остался незакрытый
print(is_balanced("")) # True
Ключевые случаи:
- Лишняя закрывающая → стек пуст при попытке
pop → False.
- Несовпадение пары → False.
- Лишняя открывающая → в конце стек непустой → False.
Это типичное применение стека (LIFO). Сложность $O(n)$ по времени и памяти.