部分思想及代码转载自:https://blog.csdn.net/alps1992/article/details/41741811
一开始忘了考虑最小栈会被退栈以及还会有进栈的数问题代码报废
每次更新 时间复杂度O(n),过高
效率高的方法,时间复杂度O(1).
我们每次入栈的时候,保存的不再是真正的数字,而是它与当前最小值的差(当前元素没有入栈的时候的最小值)。 这样我们pop和top的时候拿到栈顶元素再加上上一个最小值即可。 另外我们在push和pop的时候去更新min,这样getMin的时候就简单了,直接返回min。
O(1)的办法
这里说下如何O(1)时间内就找到,维护的变量没有变化,但是我们在堆栈内存放的元素需要与Min值产生关联。
例子:
我们进行同样的5次Push操作,压栈顺序为1 2 3 -1 4。
第一次栈存放 默认为0, Min为1. 因为此时最小就是第一个元素. 当前1-Min一定为0.
第二次栈存放2-Min=1, Min<2 所以继续为1.
第三次栈存放3-Min=2, Min<3 所以继续为1.
第四次栈存放-1-Min=-2, Min>-1 所以Min = -1.
第五次栈存放4-Min=5, Min<5 所以继续为-1.
大家看明白没?我们存放的数为x-Min.
这是Push的操作,当我们进行Pop()的时候怎么做呢,进行两次Pop()?
第一次栈顶元素5, 5>0, 弹出,返回 5+Min=4.
第二次栈顶元素-2, -2<0,弹出,返回Min. 并更新Min=Min-(-2).
那Top呢?
假如栈顶元素为5, 5>0 返回5+Min.
假如栈顶元素为-2, -2<0 返回Min.
大家发现没?实际上我们压栈的时候,压入的元素就是X-Min,那么只要压入的元素大于Min,那么存放的都是正数,而当X小于Min的时候,压入的元素(X-Min)就是负数。
所以弹栈的时候:
遇到正数,直接弹出栈顶元素(X-Min)和Min的和(X-Min+Min)就可以了。
遇到负数,说明在压入这个元素的时候Min值有更新,那个时候的Min值被更新为新插入的X. 例如Min=1,插入-1的时候,栈存放-1-Min=-2,而Min更新为新的X值(-1).则弹的时候就直接弹出Min就可以了。那么我们同时也把最小值弹出了,要更新Min,更新为当前Min-(X-下一个Min)此处比较绕,多用例子理解。(这两个是一个思路,最后的M-(X-下一个M)的具体意思:
M下其实是上一个M,这个上下是相对概念,即1,
式子展开就是:
弹栈时 X-M>0则未更新,直接弹出X
X-M<0,则更新,X<M更新,弹出M且更新,更新值如上
可以加入辅助栈,也可以采用栈的链式存储
代码:
辅助栈:
/***
思路:用两个栈实现。
一个普通栈,一个min栈(普通栈负责数据的入、出,min栈的栈顶永远保存当前元素的最小值)。
第一次入栈时,入到普通栈、min栈中。再次入往普通栈入数据时,当该数据<=min栈栈顶元素时,
也将该数据入到min栈中,否则只入到普通栈中。从普通栈出数据时,该数据==min栈栈顶数据时,
min栈也弹出栈顶元素,否则只弹出普通栈顶元素。总体思想就是min栈用于保存当前数据元素的最小值
**/
typedef struct
{
int *data1;
int *data2;
int top1;//普通
int top2;//最小
}stack; //两栈
stack *createstack()
{
stack *obj=(stack*)malloc(sizeof(stack));
obj->data1=(int *)malloc(sizeof(int)*MAXSIZE);
obj->top1=-1;
obj->data2=(int *)malloc(sizeof(int)*MAXSIZE);
obj->top2=-1;
return obj;
}
void stackpush(stack *obj,int x)
{
if(obj->top1==MAXSIZE-1&&obj->top2==MAXSIZE-1)
return;
else{
if(obj->top1==-1&&obj->top2==-1)
{
obj->top1++;//数组下标
obj->data1[obj->top1]=x;
obj->top2++;
obj->data2[obj->top2]=x;
}
else if(x<=obj->data2[obj->top2])
{
obj->top1++;
obj->data1[obj->top1]=x;
obj->top2++;
obj->data2[obj->top2]=x;
}
else{
obj->top1++;
obj->data1[obj->top1]=x;
}
}
}
void stackpop(stack *obj)
{
if(obj->top1==-1&&obj->top2==-1)
{
return;
}
else if(obj->data1[obj->top1]==obj->data2[obj->top2])
{
obj->top1--;
obj->top2--;
}
else{
obj->top1--;
}
}
int stacktop(stack *obj)
{
return obj->data1[obj->top1];
}
int stackgetmin(stack *obj)
{
return obj->data2[obj->top2];
}
int main()
{
stack *obj=createstack();
stackpush(obj,8);
stackpush(obj,0);
stackpush(obj,9);
stackpush(obj,-5);
stackpop(obj);
int a=stackgetmin(obj);
printf("%d\n",a);
}
链栈:
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <iostream>
using namespace std;
class MinStack {
public:
struct StackNode{
int num;
StackNode *next;
};
typedef StackNode* stack;
stack s;
MinStack(){
s = (stack)malloc(sizeof(struct StackNode));
s->next = NULL;
}
int min;
void push(int x) {
if (s->next == NULL) {
stack node = (stack)malloc(sizeof(struct StackNode));
node->num = x;
node->next = s->next;
s->next = node;
min = x;
}else{
stack node = (stack)malloc(sizeof(struct StackNode));
node->num = x;
node->next = s->next;
s->next = node;
if (x < min) {
min = x;
}
}
}
void pop() {
if (s->next == NULL) {
return;
}else{
stack temp = s->next;
if (min == s->next->num && s->next->next != NULL) {
s->next = s->next->next;
free(temp);
min = s->next->num;
for (stack loop = s->next; loop != NULL; loop = loop->next) {
if (min > loop->num) {
min = loop->num;
}
}
}else{
s->next = s->next->next;
free(temp);
}
}
}
int top() {
if (s->next == NULL) {
return NULL;
}
return s->next->num;
}
int getMin() {
if (s->next == NULL) {
return NULL;
}
return min;
}
};
int main(int argc, const char * argv[]) {
MinStack MinS;
MinS.push(-1);
MinS.push(0);
MinS.push(2);
MinS.push(-2);
printf("%d\n",MinS.top());
MinS.pop();
MinS.pop();
MinS.pop();
printf("%d\n",MinS.getMin());
return 0;
}
最普通方法:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
//普通法 时间复杂度O(n)
typedef struct {
int *data;
int top;
}minstack;
minstack *minstackinit()
{
minstack *obj=(minstack *)malloc(sizeof(minstack));
obj->data=(int *)malloc(sizeof(int)*MAXSIZE);
obj->top=-1;
return obj;
}
void minstackpush(minstack *obj,int x)
{
if(obj->top==MAXSIZE-1)
return;
else{
obj->top++;
obj->data[obj->top]=x;
}
}
void minstackpop(minstack *obj)
{
if(obj->top==-1)
return;
else{
obj->top--;
}
}
int minstackTop(minstack *obj)
{
if(obj->top==-1)
return 0;
return obj->data[obj->top];
}
int minstackgetmin(minstack *obj)
{
if(obj->top==-1)
return 0;
if(obj->top==0)
return obj->data[obj->top];
int min=obj->data[0];
for(int i=0;i<obj->top;i++)
{
if(obj->data[i]<min)
min=obj->data[i];
}
return min;
}
int main()
{
minstack *obj=minstackinit();
minstackpush(obj,8);
minstackpush(obj,21);
minstackpush(obj,6);
minstackpop(obj);
printf("%d\n",minstackTop(obj));
int a=minstackgetmin(obj);
printf("%d\n",a);
}
差值法:
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.min = float('inf')
self.stack = []
def push(self, x: int) -> None:
self.stack.append(x - self.min)
if x < self.min:
self.min = x
def pop(self) -> None:
if not self.stack:
return
tmp = self.stack.pop()
if tmp < 0:
self.min -= tmp
def top(self) -> int:
if not self.stack:
return
tmp = self.stack[-1]
if tmp < 0:
return self.min
else:
return self.min + tmp
def getMin(self) -> int:
return self.min
做题确实有助于对知识的理解,栈不管是什么形式构造只要保持其基本特点即可,之前有点拘泥于课本上的形式了
部分代码及思路链接:
https://blog.csdn.net/alps1992/article/details/41741811
https://github.com/azl397985856/leetcode/blob/master/problems/155.min-stack.md