Задача: создать очередь с помощью стеков
Решаем задачи, которые дают программистам на собеседованиях в IT-компаниях. Сегодня пытаемся понять, как сделать очередь из нескольких стеков.
Иллюстрация: Polina Vari для Skillbox Media
Сергей Голицын
Senior Java Developer в Covalent Inc. и преподаватель. Больше семи лет в Java-разработке. В свободное время судит хакатоны и делится опытом с начинающими программистами. Пишет статьи для «Хабра» и Medium. Ведёт телеграм-каналы «Полезные ссылки около Java» и Cracking code interview.
Условие. Реализовать first-in-first-out (FIFO) очередь, используя максимум два стека. Она должна поддерживать все стандартные функции обычной очереди — push, pop, peek и empty.
- push — добавляет элемент в конец очереди;
- pop — убирает элемент из начала и возвращает его как результат;
- peek — возвращает элемент из начала очереди, но не убирает его;
- empty — возвращает true, если очередь пустая, иначе — false.
Примечание: вы должны использовать только стандартные операции со стеками — push, peek/pop, size и empty. А если ваш язык не поддерживает стеки, то их можно реализовать через обычный список или двустороннюю очередь, но при этом использовать только функции, приведённые выше.
Ввод и вывод. Пример 1
Решить эту задачу самостоятельно и на разных языках программирования можно на LeetCode. Наше решение взято из телеграм-канала Сергея Cracking code interview.
Решение
Мы будем решать задачу с помощью двух стеков. Самое сложное — реализовать методы pop и peak. Но для начала давайте создадим наш класс:
Теперь давайте реализуем метод push:
Всё просто — добавляем новый элемент в стек current.
Теперь давайте напишем метод pop. Для него нам нужно переместить все элементы из стека current в стек tmp. А перед этим — проверить стек tmp: если в нём есть элементы, то нам просто нужно вернуть элемент из этого стека.
В виде кода это выглядит так:
Чтобы продемонстрировать правильность работы этой фукнции, давайте посмотрим на пример:
- push 1 → 1;
- push 2 → 2, 1;
- push 3 → 3, 2, 1;
- pop → перемещаем всё в tmp: cur: 2, 1; tmp: 3 → cur: 1; tmp: 2, 3 → cur: ; tmp: 1, 2, 3;
- теперь все элементы в tmp стоят в правильном порядке.
Получается, когда мы переносим элементы из одного стека в другой, этот процесс похож на функцию insert для очередей. Поэтому оно и работает.
Теперь по похожей логике давайте напишем функцию peek:
И последнее — метод empty:
Здесь нам важно не забыть проверить вторую очередь.
Результаты
Временная сложность: лучший случай — O(1), худший — O(n).
Ёмкостная сложность: O(1) — нам нужно заранее определённое количество места в памяти.