РЕДАКТИРОВАТЬ: Это не соответствует ограничению «постоянного пространства» - оно в основном удваивает необходимое пространство. Я очень сомневаюсь, что есть решение, которое не делает этого, хотя где-то не разрушает сложность выполнения (например, делает push / pop O (n)). Обратите внимание, что это не меняет сложность требуемого пространства, например, если у вас есть стек с требованиями к пространству O (n), это все равно будет O (n) только с другим постоянным коэффициентом.
Решение в непостоянном пространстве
Храните «дублирующуюся» стопку «минимум всех значений ниже в стопке». Когда вы открываете основную стопку, вытаскиваете и минимальную стопку. Когда вы нажимаете основной стек, нажимайте либо новый элемент, либо текущий минимум, в зависимости от того, что меньше. getMinimum()
затем реализуется как просто minStack.peek()
.
Итак, используя ваш пример, у нас было бы:
Real stack Min stack
5 --> TOP 1
1 1
4 2
6 2
2 2
После двойного нажатия вы получите:
Real stack Min stack
4 2
6 2
2 2
Пожалуйста, дайте мне знать, если этой информации недостаточно. Наощупь это просто, но поначалу может понадобиться немного почесать голову :)
(Обратной стороной, конечно же, является то, что это вдвое увеличивает потребность в пространстве. Однако время выполнения не сильно страдает - т.е. это все та же сложность.)
EDIT: есть вариант, который немного сложнее, но в целом имеет лучшее место. У нас все еще есть минимальный стек, но мы выходим из него только тогда, когда значение, которое мы извлекаем из основного стека, равно значению в минимальном стеке. Мы отправляем в стек min только тогда, когда значение, помещаемое в основной стек, меньше или равно текущему минимальному значению. Это позволяет дублировать минимальные значения. getMinimum()
это все еще лишь небольшая операция. Например, если взять исходную версию и снова нажать 1, мы получим:
Real stack Min stack
1 --> TOP 1
5 1
1 2
4
6
2
Выскакивание из вышеуказанного появляется из обоих стеков, потому что 1 == 1, в результате чего:
Real stack Min stack
5 --> TOP 1
1 2
4
6
2
Выталкивание снова происходит только из основного стека, потому что 5> 1:
Real stack Min stack
1 1
4 2
6
2
Выталкивание снова открывает оба стека, потому что 1 == 1:
Real stack Min stack
4 2
6
2
В результате получается такая же сложность пространства наихудшего случая (удвоение исходного стека), но гораздо лучшее использование пространства, если мы редко получаем «новый минимум или равный».
РЕДАКТИРОВАТЬ: Вот реализация злой схемы Пита. Тщательно не тестировал, но думаю , ничего страшного :)
using System.Collections.Generic;
public class FastMinStack<T>
{
private readonly Stack<T> stack = new Stack<T>();
// Could pass this in to the constructor
private readonly IComparer<T> comparer = Comparer<T>.Default;
private T currentMin;
public T Minimum
{
get { return currentMin; }
}
public void Push(T element)
{
if (stack.Count == 0 ||
comparer.Compare(element, currentMin) <= 0)
{
stack.Push(currentMin);
stack.Push(element);
currentMin = element;
}
else
{
stack.Push(element);
}
}
public T Pop()
{
T ret = stack.Pop();
if (comparer.Compare(ret, currentMin) == 0)
{
currentMin = stack.Pop();
}
return ret;
}
}
Добавьте поле для хранения минимального значения и обновите его во время Pop () и Push (). Таким образом, getMinimum () будет O (1), но Pop () и Push () должны будут сделать немного больше.
Если выбрано минимальное значение, Pop () будет O (n), в противном случае они все равно будут O (1). При изменении размера Push () становится O (n) в соответствии с реализацией Stack.
Вот быстрая реализация
источник
Он явно сохраняет текущий минимум, и если минимум изменяется, вместо того, чтобы нажимать значение, он выдвигает значение с той же разницей, что и другая сторона нового минимума (если min = 7 и вы нажимаете 5, он нажимает 3 вместо этого (5- | 7-5 | = 3) и устанавливает min в 5; если вы затем вытолкнете 3, когда min равно 5, он увидит, что всплывающее значение меньше min, поэтому отменяет процедуру, чтобы получить 7 для нового min, а затем возвращает предыдущее мин). Поскольку любое значение, которое не вызывает изменения, текущий минимум больше текущего минимума, у вас есть кое-что, что можно использовать для различения значений, которые изменяют минимум, и тех, которые не изменяют.
В языках, которые используют целые числа фиксированного размера, вы занимаетесь небольшим пространством из представления значений, поэтому оно может быть переполнено, и утверждение не будет выполнено. Но в остальном это постоянное лишнее пространство, и все операции по-прежнему O (1).
Стеки, которые вместо этого основаны на связанных списках, имеют другие места, из которых вы можете позаимствовать бит, например, в C младший бит следующего указателя или в Java - тип объектов в связанном списке. Для Java это означает, что используется больше места по сравнению с непрерывным стеком, поскольку у вас есть накладные расходы объекта на ссылку:
В C накладных расходов нет, и вы можете позаимствовать lsb следующего указателя:
Однако ни один из них не является O (1). На практике им не нужно больше места, потому что они используют дыры в представлениях чисел, объектов или указателей на этих языках. Но теоретическая машина, которая использовала более компактное представление, потребовала бы добавления дополнительного бита к этому представлению в каждом случае.
источник
pop()
если последнееInteger.MIN_VALUE
переданное значение было (например, push 1, push Integer.MIN_VALUE, pop). Это связано с переполнением, как упоминалось выше. В противном случае работает для всех целочисленных значений.Я нашел решение, которое удовлетворяет всем упомянутым ограничениям (операции с постоянным временем) и постоянным дополнительным пространством .
Идея состоит в том, чтобы сохранить разницу между минимальным значением и входным числом и обновить минимальное значение, если оно больше не является минимальным.
Код выглядит следующим образом:
Кредит принадлежит: https://leetcode.com/discuss/15679/share-my-java-solution-with-only-one-stack
источник
Ну, а каковы ограничения времени выполнения
push
иpop
? Если они не должны быть постоянными, просто вычислите минимальное значение в этих двух операциях (сделав их O ( n )). В противном случае я не понимаю, как это можно сделать с постоянным дополнительным пространством.источник
Вот мой код, который работает с O (1). В предыдущем коде, который я опубликовал, была проблема, когда выскакивал минимальный элемент. Я изменил свой код. Этот использует другой стек, который поддерживает минимальный элемент, присутствующий в стеке над текущим перемещенным элементом.
источник
Я использовал другой стек. Вот реализация.
Вывод:
Попытайся. Думаю, это ответ на вопрос. Второй элемент каждой пары дает минимальное значение, наблюдаемое при вставке этого элемента.
источник
Я размещаю здесь полный код, чтобы найти min и max в заданном стеке.
Сложность времени будет O (1) ..
Сообщите мне, если у вас возникнут проблемы
Спасибо, Викаш
источник
Вы можете расширить свой исходный класс стека и просто добавить к нему минимальное отслеживание. Пусть исходный родительский класс обрабатывает все остальное как обычно.
источник
Вот мое решение на java с использованием списка понравившихся.
}
источник
Предположим, стек, над которым мы будем работать, следующий:
В приведенном выше представлении стек строится только по левому значению, правое значение [minvalue] записано только для иллюстрации, которое будет храниться в одной переменной.
Фактическая проблема заключается в том, что когда значение, которое является минимальным значением, удаляется в этот момент, как мы можем узнать, какой будет следующий минимальный элемент, без повторения по стеку.
Как, например, в нашем стеке, когда появляется 6 get, мы знаем, что это не минимальный элемент, потому что минимальный элемент равен 2, поэтому мы можем безопасно удалить его, не обновляя наше минимальное значение.
Но когда мы выдвигаем 2, мы видим, что минимальное значение сейчас равно 2, и если этот get выскочил, нам нужно обновить минимальное значение до 3.
Point1:
Теперь, если вы внимательно понаблюдаете, нам нужно сгенерировать minvalue = 3 из этого конкретного состояния [2, minvalue = 2]. или если вы опускаетесь в стек, нам нужно сгенерировать minvalue = 7 из этого конкретного состояния [3, minvalue = 3], или если вы углубитесь в стек, нам нужно сгенерировать minvalue = 8 из этого конкретного состояния [7, minvalue = 7]
Вы заметили что-то общее во всех трех вышеупомянутых случаях: значение, которое нам нужно сгенерировать, зависит от двух переменных, которые обе равны. Верный. Почему это происходит, потому что, когда мы нажимаем какой-то элемент меньше текущего minvalue, мы в основном помещаем этот элемент в стек и обновляем то же число в minvalue.
Point2:
Таким образом, мы в основном сохраняем дубликат одного и того же числа один раз в стеке и один раз в переменной minvalue. Нам нужно сосредоточиться на том, чтобы избежать этого дублирования и сохранить какие-то полезные данные в стеке или minvalue, чтобы сгенерировать предыдущий минимум, как показано в СЛУЧАЯХ выше.
Давайте сосредоточимся на том, что мы должны хранить в стеке, когда значение, сохраняемое в push, меньше минимального значения. Назовем эту переменную y, так что теперь наш стек будет выглядеть примерно так:
Я переименовал их в y1, y2, y3, чтобы избежать путаницы, что все они будут иметь одинаковое значение.
Point3:
Теперь попробуем найти некоторые ограничения по y1, y2 и y3. Вы помните, когда именно нам нужно обновить minvalue при выполнении pop (), только когда мы вытащили элемент, который равен minvalue. Если мы извлекаем что-то большее, чем minvalue, нам не нужно обновлять minvalue. Таким образом, чтобы запустить обновление minvalue, y1, y2 и y3 должны быть меньше, чем соответствующее minvalue. [Мы поддерживаем равенство, чтобы избежать дублирования [Point2]], поэтому ограничение равно [y <minValue].
Теперь давайте вернемся к заполнению y, нам нужно сгенерировать какое-то значение и поместить y во время нажатия, помните. Давайте возьмем значение, которое приходит для push, равным x, которое меньше, чем prevMinvalue, а значение, которое мы фактически поместим в стек, равным y. Итак, очевидно одно: newMinValue = x и y <newMinvalue.
Теперь нам нужно вычислить y (помните, что y может быть любым числом, которое меньше newMinValue (x), поэтому нам нужно найти какое-то число, которое может выполнить наше ограничение) с помощью prevMinvalue и x (newMinvalue).
Итак, во время нажатия x, если оно меньше prevMinvalue, мы нажимаем y [2 * x-prevMinValue] и обновляем newMinValue = x.
И во время pop, если стек содержит что-то меньшее, чем minValue, это наш триггер для обновления minVAlue. Нам нужно вычислить prevMinValue из curMinValue и y. y = 2 * curMinValue - prevMinValue [доказано] prevMinVAlue = 2 * curMinvalue - y.
2 * curMinValue - y - это число, которое нам нужно обновить до prevMinValue.
Код для той же логики приведен ниже с O (1) временной и O (1) пространственной сложностью.
источник
Вот мой вариант реализации.
источник
источник
Я нашел это решение здесь
источник
источник
источник
источник
Вот мой код, который работает с O (1). Здесь я использовал пару векторов, которые содержат значение, которое было выдвинуто, а также содержат минимальное значение до этого значения.
Вот моя версия реализации на C ++.
источник
источник
Class
-MinStack
? Документация Oracle по Java рекомендует использоватьDeque
.Практическая реализация для поиска минимума в стеке объектов, созданных пользователем, с именем: Школа
Stack будет хранить школы в стеке на основе ранга, присвоенного школе в конкретном регионе, скажем, findMin () дает школу, в которой мы получаем максимальное количество заявок на прием, которое, в свою очередь, должно определяться компаратор, который использует рейтинг, связанный со школами в предыдущем сезоне.
Также школьный объект выглядит следующим образом:
Этот пример охватывает следующее: 1. Реализация стека для объектов, определенных пользователем, здесь Школа 2. Реализация методов hashcode () и equals () с использованием всех полей сравниваемых объектов 3. Практическая реализация сценария, в котором мы rqeuire, чтобы получить операцию, содержащуюся в стеке, в порядке O (1)
источник
language-agnostic
: укажите, что вы используете для кода (и удалите пробелы перед этимThe Code for same is below:
). Как это поддерживаетсяstack.pop()
? (иpush()
?)Вот реализация PHP того, что объясняется в ответе Джона Скита как немного лучшая реализация сложности пространства для получения максимума стека в O (1).
источник
Вот реализация ответа Джона Скитса на C ++ . Возможно, это не самый оптимальный способ реализации, но он делает именно то, что должен.
А вот и драйвер для класса
Вывод:
источник
Мы можем сделать это за время O (n) и сложность пространства O (1), например:
источник
Я думаю, вы можете просто использовать LinkedList в своей реализации стека.
В первый раз, когда вы нажимаете значение, вы помещаете это значение в заголовок связанного списка.
затем каждый раз, когда вы нажимаете значение, если новое значение <head.data, выполняйте операцию предварительной обработки (что означает, что голова становится новым значением)
если нет, то выполните операцию добавления.
Когда вы делаете pop (), вы проверяете, есть ли min == connectedlist.head.data, если да, то head = head.next;
Вот мой код.
источник
источник
источник
Увидел здесь блестящее решение: https://www.geeksforgeeks.org/design-a-stack-that-supports-getmin-in-o1-time-and-o1-extra-space/
Ниже приведен код Python, который я написал, следуя алгоритму:
источник
Чтобы получить элементы Min из Stack. Мы должны использовать два стека .ie Stack s1 и Stack s2.
--------------------- Рекурсивно вызывать шаги 2–4 -----------------------
если Новый элемент добавлен в стек s1.Тогда выталкивает элементы из стека s2
сравнить новые элементы с s2. который меньше, нажмите на s2.
pop из стека s2 (который содержит минимальный элемент)
Код выглядит так:
источник
Думаю страдает только операция push, хватит. Моя реализация включает стек узлов. Каждый узел содержит элемент данных, а также минимум на тот момент. Этот минимум обновляется каждый раз, когда выполняется операция push.
Вот несколько моментов для понимания:
Я реализовал стек с помощью связанного списка.
Верхний указатель всегда указывает на последний нажатый элемент. Когда в этом стеке нет элемента, вершина NULL.
Когда элемент выталкивается, выделяется новый узел, у которого есть следующий указатель, указывающий на предыдущий стек, и обновляется вершина, указывающая на этот новый узел.
Единственное отличие от обычной реализации стека заключается в том, что во время push он обновляет член min для нового узла.
Пожалуйста, взгляните на код, который реализован на C ++ в демонстрационных целях.
И вывод программы выглядит так:
источник
источник