Предположим, стек, над которым мы будем работать, следующий:
6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8
В приведенном выше представлении стек строится только по левому значению, правое значение [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, так что теперь наш стек будет выглядеть примерно так:
6 , minvalue=2
y1 , minvalue=2
5 , minvalue=3
y2 , minvalue=3
9 , minvalue=7
y3 , minvalue=7
8 , minvalue=8
Я переименовал их в 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).
Let's do the math:
x < prevMinvalue [Given]
x - prevMinvalue < 0
x - prevMinValue + x < 0 + x [Add x on both side]
2*x - prevMinValue < x
this is the y which we were looking for less than x(newMinValue).
y = 2*x - prevMinValue. 'or' y = 2*newMinValue - prevMinValue 'or' y = 2*curMinValue - prevMinValue [taking curMinValue=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) пространственной сложностью.
// C++ program to implement a stack that supports
// getMinimum() in O(1) time and O(1) extra space.
#include <bits/stdc++.h>
using namespace std;
// A user defined stack that supports getMin() in
// addition to push() and pop()
struct MyStack
{
stack<int> s;
int minEle;
// Prints minimum element of MyStack
void getMin()
{
if (s.empty())
cout << "Stack is empty\n";
// variable minEle stores the minimum element
// in the stack.
else
cout <<"Minimum Element in the stack is: "
<< minEle << "\n";
}
// Prints top element of MyStack
void peek()
{
if (s.empty())
{
cout << "Stack is empty ";
return;
}
int t = s.top(); // Top element.
cout << "Top Most Element is: ";
// If t < minEle means minEle stores
// value of t.
(t < minEle)? cout << minEle: cout << t;
}
// Remove the top element from MyStack
void pop()
{
if (s.empty())
{
cout << "Stack is empty\n";
return;
}
cout << "Top Most Element Removed: ";
int t = s.top();
s.pop();
// Minimum will change as the minimum element
// of the stack is being removed.
if (t < minEle)
{
cout << minEle << "\n";
minEle = 2*minEle - t;
}
else
cout << t << "\n";
}
// Removes top element from MyStack
void push(int x)
{
// Insert new number into the stack
if (s.empty())
{
minEle = x;
s.push(x);
cout << "Number Inserted: " << x << "\n";
return;
}
// If new number is less than minEle
if (x < minEle)
{
s.push(2*x - minEle);
minEle = x;
}
else
s.push(x);
cout << "Number Inserted: " << x << "\n";
}
};
// Driver Code
int main()
{
MyStack s;
s.push(3);
s.push(5);
s.getMin();
s.push(2);
s.push(1);
s.getMin();
s.pop();
s.getMin();
s.pop();
s.peek();
return 0;
}