Стек и задача с собеседования

В этом уроке ты
  • Научишься применять стек на практике.
  • Решишь с помощью стека популярную задачу с собеседования.
  • Оценишь сложность решения задачи по времени и памяти.
Задача с собеседования
Условие

Дана строка s, которая может содержать символы (){}[], а также символы латинского алфавита. Необходимо определить, является ли строка s правильной.

Строка считается правильной, если выполняются следующие условия:

  • Каждой открывающей скобке соответствует закрывающая скобка того же типа.
  • Скобки закрываются в правильном порядке.
  • Символы латинского алфавита не влияют на правильность строки.
Пример 1
Ввод: s = "[Hello]({}({}[])())()(World)"
Вывод: true
Пример 2
Ввод: s = "()([})"
Вывод: false
Объяснение: круглую скобку пытается закрыть фигурная скобка, это неправильно.
Пример 3
Ввод: s = "())"
Вывод: false
Объяснение: закрывающих скобок больше, чем открывающих.

Решение задачи

public class Solution
{
    public static bool IsBalanced(string s)
    {
        Stack<char> stack = new Stack<char>();
        Dictionary<char, char> pairs = new Dictionary<char, char>
        {
            { '{', '}' },
            { '(', ')' },
            { '[', ']' }
        };

        foreach (char charElem in s)
        {
            if (charElem != '{' && charElem != '[' && charElem != '(' && 
                charElem != '}' && charElem != ']' && charElem != ')')
            {
                // Пропускаем все латинские символы, потому что они не влияют на результат
                continue;
            }

            if (pairs.ContainsKey(charElem))
            {
                // Если скобка открытая - просто добавляем в стек
                stack.Push(charElem);
                continue;
            }

            // Перед нами закрывающаяся скобка, но стек пуст
            if (stack.Count == 0)
            {
                return false;
            }

            // Удаляем последний элемент из стека
            char lastChar = stack.Pop();

            // Проверяем, что последний элемент в стеке и текущий образуют пару
            // Если пару не образуют, то возвращаем false
            if (pairs[lastChar] != charElem)
            {
                return false;
            }
        }

        // Если стек пуст, значит все скобки сбалансированы
        return stack.Count == 0;
    }
}

Используем стек, чтобы хранить открывающие скобки и проверять, соответствует ли им каждая закрывающая скобка. Если мы встретим несоответствие или стек окажется не пуст в конце, то строка неправильная.

Сложность работы со стеком

При работе со стеком самая сложная часть — придумать правильные условия, когда добавлять элементы в стек и когда их удалять. Чем больше задач на эту тему ты решишь, тем легче тебе будет находить решения таких задач в будущем.

Чаще всего стек используется:

  • для проверки правильности последовательности скобок;
  • когда для формирования ответа нужно использовать предыдущие значения или состояния.

Это не единственные примеры применения стека, но они помогут тебе освоиться на начальном этапе.

Что дальше

Теперь переходи к решению задач, чтобы закрепить новые знания на практике!