题目
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。 pop() —— 删除栈顶的元素。 top() —— 获取栈顶元素。 getMin() ——
检索栈中的最小元素。示例:
输入: [“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]输出: [null,null,null,null,-3,null,0,-2]
解释: MinStack minStack = new MinStack(); minStack.push(-2);
minStack.push(0); minStack.push(-3); minStack.getMin(); --> 返回 -3.
minStack.pop(); minStack.top(); --> 返回 0. minStack.getMin();
–> 返回 -2.提示:
pop、top 和 getMin 操作总是在 非空栈 上调用。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/min-stack
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析
要做出这道题目,首先要理解栈结构先进后出的性质。
对于栈来说,如果一个元素 a 在入栈时,栈里有其它的元素 b, c, d,那么无论这个栈在之后经历了什么操作,只要 a 在栈中,b, c, d 就一定在栈中,因为在 a 被弹出之前,b, c, d 不会被弹出。
因此,在操作过程中的任意一个时刻,只要栈顶的元素是 a,那么我们就可以确定栈里面现在的元素一定是 a, b, c, d。
那么,我们可以在每个元素 a 入栈时把当前栈的最小值 m 存储起来。在这之后无论何时,如果栈顶元素是 a,我们就可以直接返回存储的最小值 m。
按照上面的思路,我们只需要设计一个数据结构,使得每个元素 a 与其相应的最小值 m 时刻保持一一对应。因此我们可以使用一个辅助栈,与元素栈同步插入与删除,用于存储与每个元素对应的最小值。
当一个元素要入栈时,我们取当前辅助栈的栈顶存储的最小值,与当前元素比较得出最小值,将这个最小值插入辅助栈中;
- 当一个元素要出栈时,我们把辅助栈的栈顶元素也一并弹出;
- 在任意一个时刻,栈内元素的最小值就存储在辅助栈的栈顶元素中。
代码
#define STACK_MAX 1000
typedef struct {
int top;
int data[STACK_MAX];
} MyStack;
typedef struct {
MyStack stackAll;
MyStack stackMin;
} MinStack;
MinStack *minStackCreate() {
MinStack *stack = malloc(sizeof(MinStack));
stack->stackAll.top = -1;
stack->stackMin.top = -1;
return stack;
}
void minStackPush(MinStack *obj, int x) {
//只判断stackAll即可,stackMin的数据小于等于stackAll
if (obj->stackAll.top == (STACK_MAX - 1))
return;
//stackAll保存所有数据,都要入栈
obj->stackAll.data[++obj->stackAll.top] = x;
//stackMin保存最小数据,入栈前需要判断栈顶值
if (-1 == obj->stackMin.top || x <= obj->stackMin.data[obj->stackMin.top]) {
obj->stackMin.data[++obj->stackMin.top] = x;
}
}
void minStackPop(MinStack *obj) {
if (obj->stackAll.top == -1)
return;
if (obj->stackAll.data[obj->stackAll.top] == obj->stackMin.data[obj->stackMin.top]) {
obj->stackMin.top--;
}
obj->stackAll.top--;
}
int minStackTop(MinStack *obj) {
return obj->stackAll.data[obj->stackAll.top];
}
int minStackGetMin(MinStack *obj) {
return obj->stackMin.data[obj->stackMin.top];
}
void minStackFree(MinStack *obj) {
free(obj);
}
结果
效果勉强凑活。还有没有其他方法呢?
分析
上面的解法用了两个栈,辅助栈的操作比较有限。所以其实一个栈就可以实现两个栈的作用效果,当push时入栈两个元素,分别是当前命令需要入栈的元素和栈中所有元素的最小值;出栈的时候同时出两个元素,丢弃最小值元素,返回所需要的元素;获取最小值时就需要返回栈中第二个元素。
还有一种是我在栈中记录最小值,当元素进栈时判断是否更新最小值,当元素出栈的时候,若出栈元素等于最小值,则进行更新最小值。
这两种方法中,我感觉后者明显更优秀,但是后者更新最小值的时候需要遍历一遍栈中所有元素。代码如下:
代码2
typedef struct {
int val[10000];
int min;
int len;
int count;
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() {
MinStack* obj= (MinStack*)calloc(1,sizeof(MinStack));
obj->count = 0;
obj->len = 10000;
obj->min = INT_MAX;
return obj;
}
void minStackPush(MinStack* obj, int x) {
if(obj->count<obj->len){
obj->val[obj->count++] = x;
if(obj->min>x)
obj->min = x;
}
}
void minStackPop(MinStack* obj) {
if(obj->count>0){
obj->count--;
}
int x = INT_MAX;
for(int i = 0;i<obj->count;i++) {
if(obj->val[i]<x)
x = obj->val[i];
}
obj->min = x;
}
int minStackTop(MinStack* obj) {
if(obj->count>0)
return obj->val[obj->count-1];
return 0;
}
int minStackGetMin(MinStack* obj) {
if(obj->count>0)
return obj->min;
return 0;
}
void minStackFree(MinStack* obj) {
obj->count = 0;
obj->min = INT_MIN;
}
运行结果
效果还可以吧。