Üzerinde çalışacağımız yığının şu olduğunu varsayalım:
6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8
Yukarıdaki gösterimde, yığın yalnızca sol değer tarafından oluşturulur, sağ değerin [minvalue] yalnızca bir değişkende saklanacak örnekleme amacıyla yazılır.
Asıl Sorun, minimum değer olan değerin bu noktada kaldırıldığı zamandır, yığın üzerinde yinelemeden bir sonraki minimum öğenin ne olduğunu nasıl bilebiliriz.
Örneğin yığınımızdaki 6 get atıldığında bunun minimum eleman olmadığını biliyoruz çünkü minimum eleman 2'dir, bu yüzden bunu minimum değerimizi güncellemeden güvenle kaldırabiliriz.
Ancak 2'yi açtığımızda, şu anda minimum değerin 2 olduğunu görebiliriz ve bu ortaya çıkarsa minimum değeri 3 olarak güncellememiz gerekir.
1. Nokta:
Şimdi dikkatlice gözlemlerseniz, bu belirli durumdan [2, minvalue = 2] minvalue = 3 üretmemiz gerekir. ya da yığın depperine giderseniz, bu belirli durumdan [3, minvalue = 3] minvalue = 7 oluşturmamız gerekir ya da yığın içinde daha depper giderseniz, bu belirli durumdan [7, minvalue] minvalue = 8 oluşturmamız gerekir = 7]
Yukarıdaki 3 durumun hepsinde ortak bir şey fark ettiniz mi, üretmemiz gereken değer, her ikisi de eşit olan iki değişkene bağlıdır. Doğru. Bu neden oluyor çünkü bazı elementleri mevcut minvalue'dan daha küçük ittiğimizde, temelde o elementi yığına itiyoruz ve aynı sayıyı minvalue'da da güncelliyoruz.
Nokta2'ye:
Yani temelde aynı sayının bir kopyasını bir yığınta ve bir kez de minvalue değişkeninde depoluyoruz. Bu yinelemeden kaçınmaya odaklanmalıyız ve yukarıdaki CASES'te gösterildiği gibi önceki minimum değeri oluşturmak için yığında veya minvalue'da yararlı bir şeyler depolamalıyız.
Push'da depolanacak değer minmumvalue'dan daha az olduğunda yığında neyi depolamamız gerektiğine odaklanalım. Bu değişkeni y olarak adlandıralım, şimdi yığımız şöyle görünecek:
6 , minvalue=2
y1 , minvalue=2
5 , minvalue=3
y2 , minvalue=3
9 , minvalue=7
y3 , minvalue=7
8 , minvalue=8
Hepsinin aynı değere sahip olacağına dair karışıklığı önlemek için onları y1, y2, y3 olarak yeniden adlandırdım.
Point3:
Şimdi y1, y2 ve y3 üzerinde bazı kısıtlamalar bulmaya çalışalım. Pop () yaparken minvalue'yu tam olarak ne zaman güncellememiz gerektiğini hatırlıyor musunuz, sadece minvalue'a eşit olan elementi açtığımızda. Minvalue'dan daha büyük bir şey açarsak, minvalue'yu güncellememiz gerekmez. Dolayısıyla, minvalue güncellemesini tetiklemek için, y1, y2 ve y3 oradaki minvalue'dan daha küçük olmalıdır. [[Point2]] 'nin yinelenmesini önlemek için eşitlikten kaçınıyoruz, bu nedenle kısıt [y <minValue].
Şimdi y'yi doldurmak için geri dönelim, itme anında bir değer üretmeli ve y koymalıyız, unutmayın. İtme için gelen değeri x, yani prevMinvalue'dan daha az ve aslında yığında iteceğimiz değeri y olarak alalım. Bir şey açıktır ki, newMinValue = x ve y <newMinvalue.
Şimdi prevMinvalue ve x (newMinvalue) yardımıyla y'yi hesaplamamız gerekiyor (y'nin newMinValue (x) 'den daha küçük bir sayı olabileceğini hatırlayın, bu yüzden bizim kısıtımızı karşılayabilecek bir sayı bulmamız gerekiyor).
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].
Dolayısıyla, x'i itme anında, eğer prevMinvalue'dan küçükse, o zaman y [2 * x-prevMinValue] 'a göndeririz ve newMinValue = x'i güncelleriz.
Ve pop anında eğer yığın minValue'dan daha az bir şey içeriyorsa, o zaman minVAlue'yu güncellemek için tetikleyicimiz budur. CurMinValue ve y'den prevMinValue'yu hesaplamamız gerekiyor. y = 2 * curMinValue - prevMinValue [Kanıtlanmış] prevMinVAlue = 2 * curMinvalue - y.
2 * curMinValue - y, prevMinValue'a şimdi güncellememiz gereken sayıdır.
Aynı mantık için kod aşağıda O (1) zamanı ve O (1) uzay karmaşıklığı ile paylaşılmıştır.
// 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;
}