Załóżmy, że stos, nad którym będziemy pracować, jest następujący:
6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8
W powyższej reprezentacji stos jest budowany tylko przez lewą wartość, a [minvalue] prawej wartości jest zapisywana tylko w celach ilustracyjnych, która będzie przechowywana w jednej zmiennej.
Rzeczywisty problem polega na tym, że wartość, która jest minimalną wartością get, jest usuwana w tym momencie, skąd możemy wiedzieć, jaki jest następny minimalny element bez iteracji po stosie.
Na przykład w naszym stosie, gdy wyskoczyło 6 get, wiemy, że nie jest to element minimalny, ponieważ element minimalny wynosi 2, więc możemy bezpiecznie usunąć to bez aktualizowania naszej wartości min.
Ale kiedy wyskoczymy 2, widzimy, że minimalna wartość wynosi teraz 2, a jeśli to get wyskoczyło, musimy zaktualizować minimalną wartość do 3.
Punkt 1:
Teraz, jeśli przyjrzysz się uważnie, musimy wygenerować minvalue = 3 z tego konkretnego stanu [2, minvalue = 2]. lub jeśli pójdziesz depper w stosie, musimy wygenerować minvalue = 7 z tego konkretnego stanu [3, minvalue = 3] lub jeśli pójdziesz bardziej depper w stosie, musimy wygenerować minvalue = 8 z tego konkretnego stanu [7, minvalue = 7]
Czy zauważyłeś coś wspólnego we wszystkich powyższych 3 przypadkach, wartość, którą musimy wygenerować, zależy od dwóch zmiennych, które są równe. Poprawny. Dlaczego tak się dzieje, ponieważ kiedy przesuwamy jakiś element mniejszy niż bieżąca minvalue, to po prostu umieszczamy ten element na stosie i aktualizujemy tę samą liczbę również w minvalue.
Punkt 2:
Więc w zasadzie przechowujemy duplikat tej samej liczby raz na stosie i raz w zmiennej minvalue. Musimy skupić się na unikaniu tego powielania i przechowywać jakieś przydatne dane na stosie lub minimalną wartość, aby wygenerować poprzednie minimum, jak pokazano w przypadku powyżej.
Skoncentrujmy się na tym, co powinniśmy przechowywać na stosie, gdy wartość do przechowywania w push jest mniejsza niż minimalna wartość. Nazwijmy tę zmienną y, więc teraz nasz stos będzie wyglądał mniej więcej tak:
6 , minvalue=2
y1 , minvalue=2
5 , minvalue=3
y2 , minvalue=3
9 , minvalue=7
y3 , minvalue=7
8 , minvalue=8
Zmieniłem ich nazwy na y1, y2, y3, aby uniknąć nieporozumień, że wszystkie będą miały taką samą wartość.
Punkt3:
Teraz spróbujmy znaleźć jakieś ograniczenie na y1, y2 i y3. Czy pamiętasz, kiedy dokładnie musimy zaktualizować minvalue podczas wykonywania pop (), tylko wtedy, gdy usunęliśmy element, który jest równy minvalue. Jeśli wystrzelimy coś większego niż minvalue, nie musimy aktualizować minvalue. Tak więc, aby wyzwolić aktualizację minvalue, y1, y2 i y3 powinny być mniejsze niż odpowiadająca im minvalue. [Uwolnimy równość, aby uniknąć powielania [Point2]], więc ograniczenie wynosi [y <minValue].
Teraz wróćmy do wypełnienia y, musimy wygenerować jakąś wartość i umieścić y w momencie wypychania, pamiętaj. Przyjmijmy, że wartością, która nadchodzi dla push jest x, która jest mniejsza niż wartość prevMinvalue, a wartością, którą faktycznie wepchniemy na stosie, będzie y. Więc jedno jest oczywiste, że newMinValue = x i y <newMinvalue.
Teraz musimy obliczyć y (pamiętaj, że y może być dowolną liczbą, która jest mniejsza niż newMinValue (x), więc musimy znaleźć jakąś liczbę, która może spełnić nasze ograniczenie) za pomocą prevMinvalue i 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].
Więc w momencie wypychania x, jeśli jest mniejsze niż prevMinvalue, wtedy wciskamy y [2 * x-prevMinValue] i aktualizujemy newMinValue = x.
A w momencie pop, jeśli stos zawiera coś mniejszego niż minValue, to jest to nasz wyzwalacz do aktualizacji minVAlue. Musimy obliczyć prevMinValue z curMinValue i y. y = 2 * curMinValue - prevMinValue [Udowodniono] prevMinVAlue = 2 * curMinvalue - y.
2 * curMinValue - y to liczba, którą musimy teraz zaktualizować do prevMinValue.
Kod tej samej logiki jest wspólny poniżej ze złożonością czasu O (1) i przestrzeni 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;
}