0
点赞
收藏
分享

微信扫一扫

画解数据结构刷题之栈之单调栈

niboac 2022-05-01 阅读 69

单调栈

第一题

实现类就是typedef并用数组或int或其他类来实现这个类 

typedef struct {
  int stack[10000];
  int stacktop;
  int minstack[10000];
  int minstacktop;  

}MinStack;//辅助栈,栈顶存最小值;


MinStack* minStackCreate() 
{
    MinStack* newStack      = (MinStack *) malloc(sizeof(MinStack));
    newStack->stacktop      = 0;
    newStack->minstacktop   = 0;
    return newStack;
}

void minStackPush(MinStack* obj, int val) {
obj->stack[obj->stacktop++]=val;
if(obj->minstacktop==0||obj->minstack[obj->minstacktop-1]>=val)
{
    obj->minstack[obj->minstacktop++]=val;
}
}

void minStackPop(MinStack* obj) {
if(obj->minstack[obj->minstacktop-1]==obj->stack[obj->stacktop-1])
{
    obj->minstacktop--;
}
obj->stacktop--;
}

int minStackTop(MinStack* obj) {
return obj->stack[obj->stacktop-1];
}

int minStackGetMin(MinStack* obj) {
return obj->minstack[obj->minstacktop-1];
}

void minStackFree(MinStack* obj) {
free(obj);
}//obj是一个类,表示栈和辅助栈

知识点:

1.利用一个辅助栈来实现查找最小值,当push和pop时实时更新最小栈的顶端(最小值)

2.struct定义

typedef struct{



}minstack

第二题

 运用单调栈思想,栈里的元素(下标)单调递减,在栈里的元素下标都是未配对成功的下标,正向遍历,与栈里的元素相比较,大于就将栈顶元素移除,并继续重复操作,直到栈为空或遍历的元素小于栈里元素(因为栈是单调递减的),然后将遍历元素进栈,

最后在栈里的元素都是最后ret数组里为0的,因为没找到匹配的。

int* dailyTemperatures(int* temperatures, int temperaturesSize, int* returnSize){
int stack[100001];
int top=0;
int *ret=(int*)malloc(sizeof(int)*temperaturesSize);
memset(ret, 0, sizeof(int) * temperaturesSize);
for(int i=0;i<temperaturesSize;i++)
{
    while(top!=0&&temperatures[i]>temperatures[stack[top-1]])
    {
int temp=stack[--top];
ret[temp]=i-temp;
    }
    stack[top++]=i;
}
*returnSize=temperaturesSize;
return ret;
}

记得出栈是--top,入栈是[top++] 
 

栈模拟队列

第一题

先用线性表实现栈

typedef struct{
    int*stack;
    int stkcapicity;
    int top;
}Stack;
Stack* stackcreate(int capicity)
{
    Stack*ret=(Stack*)malloc(sizeof(Stack));//为创建一个stack类申请空间
    ret->stkcapicity=capicity;
    ret->top=0;
    return ret;
}
void stackpush(Stack*obj,int x)
{
obj->stk[obj->top++]=x;
}
void stacktop(Stack*obj)
{
    return obj->stk[obj->top-1];
}
bool stackempty(Stack*obj)
{
    return obj->top==0;
}
void free(Stack*obj)
{
    free(obj->stk);
}
MyStack*ret=malloc(sizeof(MyStack));

注意申请空间时要这么写

typedef struct{
    // 栈
    int *stack;
    // 栈中元素个数
    int stackSize;
    // 栈的容量
    int stackCapacity;
}MyStack;
MyStack* myStackCreate(int capacity){
    // 分配内存空间
    MyStack * myStack=malloc(sizeof(MyStack));
    myStack->stack=malloc(sizeof(int)*capacity);
    // 当前没有元素
    myStack->stackSize=0;
    // 栈容量
    myStack->stackCapacity=capacity;
    return myStack;
}
void mystackpush(MyStack*mystack,int val)
{
    mystack->stack[mystack->stackSize++]=val;
}
void mystackpop(MyStack*mystack)
{
    mystack->stackSize--;
}
int mystackpeek(MyStack*mystack)
{
    return mystack->stack[mystack->stackSize-1];
}//获取栈顶元素
bool mystackempty(MyStack*mystack)
{
    return mystack->stackSize==0;
}
void mystackfree(MyStack*mystack)
{
    free(mystack->stack);
}

用栈实现队列

typedef struct {
MyStack*instack;//输入栈,所有push都进去
MyStack*outstack;//用两个栈实现队列
} MyQueue;


MyQueue* myQueueCreate() {
MyQueue*ret=malloc(sizeof(MyQueue));
ret->instack=myStackCreate(100);
ret->outstack=myStackCreate(100);
return ret;
}//为类申请空间,初始化类

void myQueuePush(MyQueue* obj, int x) {
mystackpush(obj->instack,x);
}
void in2out(MyQueue*obj)
{
while(!mystackempty(obj->instack))
{
mystackpush(obj->outstack,mystackpeek(obj->instack));
mystackpop(obj->instack);
}
}//将instack的都到outstack里
int myQueuePop(MyQueue* obj) {
if(mystackempty(obj->outstack))
{
    in2out(obj);//outstack为空时,将instack的压入他
}
int x=mystackpeek(obj->outstack);
mystackpop(obj->outstack);
return x;
}//pop队列的队首元素,也就是栈的栈底元素,所以将instack里的都pop出来,push进outstack,当outstack非空时,队首元素只可能在outstack的栈顶,不可能在instack

int myQueuePeek(MyQueue* obj) {
if(mystackempty(obj->outstack))
{
    in2out(obj);
}
int x=mystackpeek(obj->outstack);
return x;
}//队首元素只有两种情况,一种是只push还没有pop过的队列,这时outstack为空,队首元素在instack的栈底,用front记录,另一种情况是已经pop过了,那么outstack不为空,队首元素为outstack的栈顶

bool myQueueEmpty(MyQueue* obj) {
return mystackempty(obj->instack)&&mystackempty(obj->outstack);
}

void myQueueFree(MyQueue* obj) {
mystackfree(obj->instack);
mystackfree(obj->outstack);
}

注意申请空间时也要为stack申请空间

辅助栈

第一题

//维护前缀和数组(乘积)
typedef struct {
int zeroindex;
int top;
int a[40001];
} ProductOfNumbers;


ProductOfNumbers* productOfNumbersCreate() {
ProductOfNumbers*ret=(ProductOfNumbers*)malloc(sizeof(ProductOfNumbers));
ret->zeroindex=-1;
ret->top=0;
return ret;
}

void productOfNumbersAdd(ProductOfNumbers* obj, int num) {
obj->a[obj->top]=num;
if(num==0)
{
    obj->a[obj->top]=1;
    obj->zeroindex=obj->top;
}
else
{
    obj->a[obj->top]=num*obj->a[obj->top-1];
}
(obj->top)++;
}

int productOfNumbersGetProduct(ProductOfNumbers* obj, int k) {
if(obj->zeroindex>obj->top-k-1)
{
    return 0;//说明倒数k个有0
}
else{
    return obj->a[obj->top-1]/obj->a[obj->top-1-k];
}
}

void productOfNumbersFree(ProductOfNumbers* obj) {
free(obj);
}

 构造前缀和数组,记录top,zeroindex(最近的0的下标)

第二题

 太难了,不像我能做出来的题

单调栈,栈里的元素的acii码单调递增

和之前的单调栈相同,如果遍历元素大于栈顶元素ascii码并且栈顶元素在之后还会出现(用哈希表记录lastindex实现),就逐个移除栈顶元素

如果栈里已经出现遍历元素,直接跳过(由bool visited【26】得到)

最大矩形

第一题

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        vector<int> left(n), right(n);
        
        stack<int> mono_stack;
        for (int i = 0; i < n; ++i) {
            while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
                mono_stack.pop();
            }
            left[i] = (mono_stack.empty() ? -1 : mono_stack.top());
            mono_stack.push(i);
        }

        mono_stack = stack<int>();
        for (int i = n - 1; i >= 0; --i) {
            while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
                mono_stack.pop();
            }
            right[i] = (mono_stack.empty() ? n : mono_stack.top());
            mono_stack.push(i);
        }
        
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans = max(ans, (right[i] - left[i] - 1) * heights[i]);
        }
        return ans;
    }
};

思路是遍历i根柱子,找到他左右第一个大于其高度的柱子,就可以计算每个柱子的最大面积

先从左往右遍历,如果单调栈非空并且遍历元素是否小于等于栈顶元素

小于就移除栈顶元素(注意是while)

随后更新当前遍历到的i元素的left【i】(即栈顶),插入i

用同样的方法从右往左遍历,记录左边的

int gettop(int*a,int top)
{
    return a[top-1];
}

int largestRectangleArea(int* heights, int heightsSize){
int stack[100001];
int top=0;
int*left=(int*)malloc(sizeof(int)*heightsSize);
int*right=(int*)malloc(sizeof(int)*heightsSize);
memset(left,0,sizeof(left));
memset(right,0,sizeof(left));
for(int i=0;i<heightsSize;i++)
{
    while(top!=0&&heights[i]<=heights[gettop(stack,top)])
    {
--top;
    }
    left[i]=top==0?-1:gettop(stack,top);
    stack[top++]=i;
}
int stack2[100001];
int top2=0;
for(int i=heightsSize-1;i>=0;--i)
{
    while(top2!=0&&heights[i]<=heights[gettop(stack2,top2)])
    {
--top2;
    }
    right[i]=top2==0?heightsSize:gettop(stack2,top2);
    stack2[top2++]=i;
}
int ans=0;
for(int i=0;i<heightsSize;++i)

{
    int temp=heights[i]*(right[i]-left[i]-1);
    ans=ans>temp?ans:temp;
}
return ans;
}

自己写的c语言版的,虽然边界溢出了

和每日温度做对比

单调栈里的元素满足单调递增或递减,都是遍历后与栈顶元素比较,决定要不要移除栈顶元素,并更新数组对应下标的值,然后将遍历元素入栈

适合做往左右第一个大于小于该值的下标

一个月了,记录一下,确实没想到自己能坚持一个月

举报

相关推荐

0 条评论