Vamos supor que a pilha na qual estaremos trabalhando seja esta:
6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8
Na representação acima, a pilha é construída apenas pelo valor à esquerda e o valor à direita [minvalue] é escrito apenas para fins de ilustração, o qual será armazenado em uma variável.
O problema real é quando o valor que é o valor mínimo é removido naquele ponto, como podemos saber qual é o próximo elemento mínimo sem iterar na pilha.
Como, por exemplo, em nossa pilha, quando 6 get's aparecem, sabemos disso, este não é o elemento mínimo porque o elemento mínimo é 2, portanto, podemos removê-lo com segurança sem atualizar nosso valor mínimo.
Mas quando estouramos 2, podemos ver que o valor mínimo é 2 agora e se esse get aparecer, precisamos atualizar o valor mínimo para 3.
Ponto 1:
Agora, se você observar cuidadosamente, precisamos gerar minvalue = 3 a partir deste estado particular [2, minvalue = 2]. ou se você for depperin a pilha, precisamos gerar minvalue = 7 a partir deste estado particular [3, minvalue = 3] ou se você for mais depperin na pilha, precisamos gerar minvalue = 8 a partir deste estado particular [7, minvalue = 7]
Você notou algo em comum em todos os 3 casos acima, o valor que precisamos gerar depende de duas variáveis que são iguais. Corrigir. Por que isso está acontecendo porque quando colocamos algum elemento menor que o minvalue atual, basicamente colocamos esse elemento na pilha e atualizamos o mesmo número em minvalue também.
Ponto 2:
Portanto, estamos basicamente armazenando duplicatas do mesmo número uma vez na pilha e uma vez na variável minvalue. Precisamos nos concentrar em evitar essa duplicação e armazenar dados úteis na pilha ou no minvalue para gerar o mínimo anterior, conforme mostrado nos CASES acima.
Vamos nos concentrar no que devemos armazenar na pilha quando o valor a ser armazenado no push é menor que o valor mínimo. Vamos chamar esta variável de y, então agora nossa pilha será parecida com isto:
6 , minvalue=2
y1 , minvalue=2
5 , minvalue=3
y2 , minvalue=3
9 , minvalue=7
y3 , minvalue=7
8 , minvalue=8
Eu os renomeei como y1, y2, y3 para evitar a confusão de que todos eles terão o mesmo valor.
Ponto 3:
Agora, vamos tentar encontrar algumas restrições sobre y1, y2 e y3. Você se lembra quando exatamente precisamos atualizar o minvalue ao fazer pop (), apenas quando tivermos exibido o elemento que é igual ao minvalue. Se exibirmos algo maior do que minvalue, não precisamos atualizar minvalue. Portanto, para acionar a atualização do minvalue, y1, y2 e y3 devem ser menores do que o minvalue correspondente. [Estamos avodando a igualdade para evitar duplicidade [Point2]], então a restrição é [y <minValue].
Agora vamos voltar para preencher y, precisamos gerar algum valor e colocar y no momento do push, lembre-se. Vamos pegar o valor que está chegando para push ser x, que é menor que prevMinvalue, e o valor que realmente colocaremos na pilha como y. Portanto, uma coisa é óbvia que newMinValue = x, ey <newMinvalue.
Agora precisamos calcular y (lembre-se de que y pode ser qualquer número menor que newMinValue (x), portanto, precisamos encontrar algum número que possa cumprir nossa restrição) com a ajuda de prevMinvalue e 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].
Portanto, no momento de pressionar x, se for menor que prevMinvalue, então pressionamos y [2 * x-prevMinValue] e atualizamos newMinValue = x.
E no momento do pop, se a pilha contiver algo menor do que minValue, esse é nosso gatilho para atualizar o minVAlue. Temos que calcular prevMinValue a partir de curMinValue e y. y = 2 * curMinValue - prevMinValue [Provado] prevMinVAlue = 2 * curMinvalue - y.
2 * curMinValue - y é o número que precisamos atualizar agora para prevMinValue.
O código para a mesma lógica é compartilhado abaixo com tempo O (1) e complexidade de espaço 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;
}