作業するスタックはこれだとしましょう:
6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8
上記の表現では、スタックは左の値によってのみ構築されます。右の値の[minvalue]は、1つの変数に格納される例示の目的でのみ書き込まれます。
実際の問題は、最小値である値がその時点で削除されたときに、スタックを反復処理せずに次の最小要素をどのようにして知ることができるかです。
たとえば、スタックで6 getがポップされたときのように、最小要素は2であるため、これは最小要素ではありません。したがって、min値を更新せずにこれを安全に削除できます。
しかし、2をポップすると、最小値は現在2であることがわかります。これがポップアウトされた場合、最小値を3に更新する必要があります。
ポイント1:
ここで注意深く観察すると、この特定の状態からminvalue = 3を生成する必要があります[2、minvalue = 2]。または、スタックでdepperを実行する場合、この特定の状態からminvalue = 7を生成する必要があります[3、minvalue = 3]またはスタックでさらにdepperを実行する場合、この特定の状態からminvalue = 8を生成する必要があります[7、minvalue = 7]
上記の3つのケースすべてに共通する点に気づきましたか?生成する必要がある値は、両方が等しい2つの変数に依存しています。正しい。現在のminvalueよりも小さい要素をプッシュすると、基本的にその要素がスタックにプッシュされ、minvalueの同じ数も更新されるため、これが発生するのはなぜですか。
ポイント2:
したがって、基本的には、スタックに1回、minvalue変数に1回、同じ数の複製を格納します。上記のCASESに示すように、この重複の回避に焦点を当て、スタックまたは最小値に有用なデータを保存して、以前の最小値を生成する必要があります。
pushに格納する値がminmumvalueより小さい場合に、スタックに何を格納するかに焦点を当てましょう。この変数に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に変更しました。
ポイント3:
次に、y1、y2、およびy3に対するいくつかの制約を見つけてみましょう。pop()の実行中に正確にminvalueを更新する必要があるのはいつか、覚えていますか。minvalueに等しい要素をポップしたときだけです。minvalueより大きい値をポップする場合、minvalueを更新する必要はありません。したがって、minvalueの更新をトリガーするには、対応するminvalueよりもy1、y2&y3を小さくする必要があります。[重複を避けるために等式を使用します[Point2]]制約は[y <minValue]です。
さて、yを入力するために戻ってみましょう。値を生成し、プッシュ時にyを置く必要があることを思い出してください。pushのために来ている値を、prevMinvalueよりも小さいxとし、スタックに実際にpushする値を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を更新します。
ポップ時にスタックにminValueより小さい値が含まれている場合、それがminVAlueを更新するトリガーになります。curMinValueとyからprevMinValueを計算する必要があります。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;
}