假设我们将要处理的堆栈是这样的:
6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8
在上面的表示中,堆栈仅由左值构建,右值的 [minvalue] 仅用于说明目的,将存储在一个变量中。
实际的问题是当最小值的值被删除时:在这一点上,我们如何知道下一个最小元素是什么而不迭代堆栈。
例如,在我们的堆栈中,当 6 被弹出时,我们知道这不是最小元素,因为最小元素是 2,所以我们可以安全地删除它而无需更新我们的最小值。
但是当我们弹出 2 时,我们可以看到最小值现在是 2,如果它被弹出,那么我们需要将最小值更新为 3。
要点1:
现在,如果您仔细观察,我们需要从这个特定状态 [2 , minvalue=2] 生成 minvalue=3。
或者如果你在堆栈中更深,我们需要从这个特定状态 [3,minvalue=3] 生成 minvalue=7,
或者如果你在堆栈中更深入,那么我们需要从这个特定状态 [7,最小值=7]
您是否注意到以上三种情况的共同点?我们需要生成的值取决于两个相等的变量。正确的。
为什么会发生这种情况,因为当我们推送一些小于当前最小值的元素时,我们基本上会将那个元素推送到堆栈中,并在最小值中更新相同的数字。
要点2:
因此,我们基本上将相同数字的副本存储一次在堆栈中,一次存储在 minvalue 变量中。
我们需要专注于避免这种重复并将一些有用的数据存储在堆栈或最小值中以生成先前的最小值,如上面的 CASES 所示。
让我们关注当要存储在 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 以避免混淆它们都将具有相同的值。
要点3:
现在让我们尝试在 y1、y2 和 y3 上找到一些约束。你还记得我们在执行 pop() 时究竟何时需要更新最小值,只有当我们弹出等于最小值的元素时。
如果我们弹出大于最小值的东西,那么我们不必更新最小值。
所以要触发minvalue的更新,y1,y2&y3应该小于对应的minvalue。[我们避免相等以避免重复[Point2]]
,因此约束是[ y < minValue ]。
现在让我们回过头来填充 y,我们需要在 push 的时候生成一些值并放入 y,记住。
让我们将推送的值设为小于 prevMinvalue 的 x,并将实际推送到堆栈中的值设为 y。
所以一件事是显而易见的,newMinValue=x,并且 y < newMinvalue。
现在我们需要在 prevMinvalue 和 x(newMinvalue) 的帮助下计算 y(记住 y 可以是任何小于 newMinValue(x) 的数字,所以我们需要找到一些可以满足我们约束的数字)。
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;
}