Ответ 1
Это классический вопрос о структурах данных. Интуиция, стоящая за проблемой, заключается в следующем: единственный способ, которым могут изменяться максимальный и минимальный, - это то, что вы вставляете новое значение в стек или выставляете новое значение из стека. Учитывая это, предположим, что на каждом уровне стека вы отслеживаете максимальные и минимальные значения на уровне или ниже этой точки в стеке. Затем, когда вы вставляете новый элемент в стек, вы можете легко (в O (1) время) вычислить максимальное и минимальное значение в любом месте стека, сравнивая новый элемент, который вы только что нажали, до текущего максимума и минимума. Аналогично, когда вы выталкиваете элемент, вы будете выставлять элемент в стеке на один шаг ниже вершины, который уже имеет максимальные и минимальные значения в остальной части стека, хранящейся рядом с ним.
Визуально предположим, что у нас есть стек и добавьте значения 2, 7, 1, 8, 3 и 9 в этом порядке. Начнем с нажатия 2, и поэтому мы нажимаем 2 на наш стек. Поскольку 2 теперь самое большое и наименьшее значение в стеке, мы записываем это:
2 (max 2, min 2)
Теперь давайте нажмем 7. Так как 7 больше 2 (текущий максимум), мы получим следующее:
7 (max 7, min 2)
2 (max 2, min 2)
Обратите внимание, что прямо сейчас мы можем прочитать max и min стека, посмотрев на верхнюю часть стека и увидев, что 7 - max, а 2 - мин. Если теперь нажать 1, получим
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
Здесь мы знаем, что 1 является минимумом, так как мы можем сравнить 1 с кешированным минимальным значением, хранящимся на стеке (2). В качестве упражнения убедитесь, что вы понимаете, почему после добавления 8, 3 и 9 мы получаем следующее:
9 (max 9, min 1)
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
Теперь, если мы хотим запросить max и min, мы можем сделать это в O (1), просто прочитав сохраненные max и min поверх стека (соответственно 9 и 1).
Теперь предположим, что мы выталкиваем верхний элемент. Это дает 9 и изменяет стек на
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
И теперь обратите внимание, что максимум этих элементов равен 8, точно правильный ответ! Если бы мы затем нажали 0, мы получим следующее:
0 (max 8, min 0)
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
И, как вы видите, max и min вычисляются правильно.
В целом, это приводит к реализации стека, который имеет O (1) push, pop, find-max и find-min, что так же асимптотически так хорошо, как и получается. Я оставлю реализацию в качестве упражнения.:-) Однако вы можете рассмотреть возможность внедрения стека с использованием одного из стандартных методов реализации стека, например, используя динамический массив или связанный список объектов, каждый из которых содержит элемент стека, min и max. Вы можете сделать это легко, используя ArrayList
или LinkedList
. В качестве альтернативы вы можете использовать предоставленный Java Stack
класс, хотя у IIRC есть некоторые накладные расходы из-за синхронизации, которая может быть ненужной для этого приложения.
Интересно, что после создания стека с этими свойствами вы можете использовать его как строительный блок для создания очереди с теми же свойствами и гарантий времени. Вы также можете использовать его в более сложной конструкции для создания очереди с двойным завершением с этими свойствами.
Надеюсь, это поможет!
EDIT: Если вам интересно, у меня есть реализации С++ min-stack и вышеупомянутый min-queue на моем личном сайте. Надеюсь, это показывает, как это может выглядеть на практике!