【问题】定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
1. 问题分析
核心思想是将每一次进入栈中的最小值保存下来。建立两个栈,一个数据 Data 栈,一个保存目前栈中最小值的 Min 栈。Data 栈用来接收用户传入的元素。Min 栈每次将传入元素与目前栈中最小值进行对比,如果小于等于,就压入栈中。故 Min 栈存在一个性质:栈顶到栈底,元素逐渐增大,栈顶元素为最小值。
例如用户传入 3 2 2 5,Data 栈接收 3,Min 栈此时为空,3 为栈最小值,故压入 Min 栈。然后传入 2,Data 栈接收 2,同时比对 2 和目前栈中最小元素(Min 栈栈顶),发现 2 比 3 小,故 2 压入 Min 栈。同理,继续传入 2 时,发现传入值小于等于目前栈中最小值,Min 栈继续压入 2。传入 5 时,发现 5 比 1 大,所以 Data 栈接收 5,而 Min 栈不接收。
压栈时,看压栈元素是否小于等于目前栈中最小值(Min 栈的栈顶元素),如果是,那么要将元素压入 Min 栈和 Data 栈各一份,否则,仅把元素压入 Data 栈。出栈时,判断出栈元素是否和 Min 栈的栈顶元素相同,如果相同,Min 栈也需要弹出相同元素。
至于为什么保存小于等于最小值的元素,而不是只保存小于的元素,其原因在于出栈操作。以传入 3 2 2 为例,如果只保存小于的元素,即 Min 栈最终结果为 3 2,Data 栈为 3 2 2。若 Data 栈弹出元素 2,Min 栈发现最小值弹出,也会弹出 2。此时 Data 栈中为 3 2,而 Min 栈中仅保留 3。结果错误,Min 栈栈顶并非栈中最小值。
2. 代码
class MinStack {
public:
/** initialize your data structure here. */
MinStack() {
}
stack<int> Data;
stack<int> Min;
void push(int x) {
Data.push(x);
// 判断是否可以进入 Min 栈:传入元素是否小于等于目前栈中最小值
if(Min.empty() || x <= Min.top()){
Min.push(x);
}
}
void pop() {
// 判断是否要出Min栈
if(Min.top() == Data.top()){
Min.pop();
}
Data.pop();
}
int top() {
return Data.top();
}
int min() {
return Min.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(x);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->min();
*/