stack的oj题

最小栈

https://leetcode.cn/problems/min-stack/icon-default.png?t=N7T8https://leetcode.cn/problems/min-stack/

题目要求我们设计一个MinStack 类, 除了提供常见的几个接口之外,还有一个getMin,使得我们能够在常数时间O(1)内获取到栈中最小的元素。

思路1:
MinStack 类里有两个成员:st就是我们正常定义的要使用的栈,min是一个辅助栈,用来帮助我们获取最小值。

1.当第一个元素入栈的时候,比如入了一个5,那我们让两个栈都push一个5, 那此时栈中的最小值就是5。
2.然后再入一个4,最小值要更新,那min_stst都push一个4(其实就是保证min_st栈顶的元素一定是最小值,最终我们就可以直接获取): 

3.然后如果再入一个6,那最小值不需要更新

那min_st要push入元素吗?可以入也可以不入,入的话再入一个4: 这样min_st栈顶的元素还是最小的。

4.pop的时候,st栈pop的话min栈也pop,两边栈的元素时刻是相同的.

当入栈的新元素小于min.top()(或第一次min_st为空)时, min入栈这个元素。

当入栈的新元素等于min.top()时, min入栈这个元素。

当入栈的新元素大于min.top()时, min入栈自己栈顶的元素。

出栈的时候,st和min同时出栈

class MinStack {
public:
    MinStack()
    {}
    
    void push(int val) 
    {
        st.push(val);
        if(min.empty())
            min.push(val);
        else if(val >= min.top())
            min.push(min.top());
        else
            min.push(val);
    }
    
    void pop()
    {
        st.pop();
        min.pop();
    }
    
    int top()
    {
        return st.top();
    }
    
    int getMin() 
    {
        return min.top();
    }

private:
    stack<int> st;
    stack<int> min;
};

 思路2:

前两步和思路一一样,入栈元素小于等于min.top()都入该元素,区别在于入栈元素大于min.top()不入该元素,而且pop也不是同步pop

MinStack 类里有两个成员:st就是我们正常定义的要使用的栈,min是一个辅助栈,用来帮助我们获取最小值。

1.当第一个元素入栈的时候,比如入了一个5,那我们让两个栈都push一个5, 那此时栈中的最小值就是5。
2.然后再入一个4,最小值要更新,那min_stst都push一个4(其实就是保证min_st栈顶的元素一定是最小值,最终我们就可以直接获取): 

3.然后如果再入一个6,那最小值不需要更新

那min_st要push入元素吗?可以入也可以不入,这里就选择不入

4.pop的时候,st栈正常pop,但只有pop的元素等于当前栈中的最小值即min.top()min才进行pop,否则min就不pop。

class MinStack {
public:
    MinStack()
    {}
    
    void push(int val) 
    {
        st.push(val);
        if(min.empty() || val <= min.top())
            min.push(val);
    }
    
    void pop()
    {
        if(st.top() ==  min.top())
             min.pop();
        st.pop();
    }
    
    int top()
    {
        return st.top();
    }
    
    int getMin() 
    {
        return min.top();
    }
private:
    stack<int> st;
    stack<int> min;
};


 栈的压入、弹出序列

https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&&tqId=11174&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-rankingicon-default.png?t=N7T8https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&&tqId=11174&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking 

比较简单的一种方法其实就是去模拟这个入栈出栈的过程,

1.首先定义一个栈, 开始入栈.

2.入栈后就开始比较,比较栈顶元素和popV中要出栈的元素是否相等,相等就pop

3.然后并没有结束,有可能st里有多个元素需要一直比较,所以只要st不为空就一直比较然后pop,栈顶元素和出栈元素不相等的话就继续入栈

4.如果最后元素全都入栈了结果还没法pop完(也就是st不为空), 就代表出栈序列是错的, 如果是正确的出栈序列,那最后栈应该是空的.

class Solution {
public:
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV)
     {
        stack<int> st;
        int i = 0,j = 0;
        while(i < pushV.size())
        {
            st.push(pushV[i++]);
            while(!st.empty() && st.top() == popV[j])
            {
                j++;
                st.pop();
            }
        }
        return st.empty();
    }
};

 逆波兰表达式求值

https://leetcode.cn/problems/evaluate-reverse-polish-notation/icon-default.png?t=N7T8https://leetcode.cn/problems/evaluate-reverse-polish-notation/

这道题目叫做逆波兰表达式求值,那什么是逆波兰表达式呢

我们正常写的表达式,就比如题目中的这个:(2 + 1) * 3
这种写法叫做中缀表达式,即运算符写在操作数的中间,但是这种写法计算机是不能直接计算的,因为涉及运算符优先级的问题,比如1+2*3,应该先算*。
所以呢,这里就需要我们做一件事情,就是把它变成后缀(逆波兰)表达式,其实就是根据优先级对表达式中的运算符排一个序,并且放到对应的操作数后面。
就比如题目中给的这个示例:((2 + 1) * 3)这个表达式对应的后缀表达式就是["2","1","+","3","*"](题中是把它放到一个字符串数组中了)。即1和2先进行后面的+,得到的结果再和3进行后面的*,得到最终结果。这样就直接从前往后算,不用考虑优先级的问题了。
 

思路

如果只是解出逆波兰表达式的值, 我们只需要借助一个栈就搞定了。
具体怎么做呢?
1.遍历给的逆波兰表达式对应的字符串数组,

2.如果对应的元素是数字,我们就让该操作数入栈

3.如果遇到操作符,我们就去取栈顶的前两个元素(并pop掉)进行对应的运算

4.然后将结果入栈,后续重复上述操作,最终栈里面唯一的那个元素就是要求的结果。
 

class Solution {
public:
    int evalRPN(vector<string>& tokens) 
    {
        stack<int> st;
        for(auto& str : tokens)
        {
            if(str =="+" || str =="-" ||str =="*" ||str =="/")
            {
                int right=st.top();
                st.pop();
                int left=st.top();
                st.pop();
                switch(str[0])//str是字符串,switch后需要是整型
                {
                    case '+':
                        st.push(left+right);
                        break;
                    case '-':
                        st.push(left-right);
                        break;
                    case '*':
                        st.push(left*right);
                        break;
                    case '/':
                        st.push(left/right);
                        break;
                }
            }
            else
            {
                st.push(stoi(str));//字符串转换成int
            }
        }
        return st.top();
    }
};

中缀表达式如何转后缀表达式

中缀表达式转后缀表达式_牛客题霸_牛客网 (nowcoder.com)

那现在大家再来思考一个问题:
如果给我们一个中缀表达式,我们如何把它转换成对应的后缀表达式

中缀转后缀呢,也是需要借助一个栈,具体怎么做呢?
比如现在有这样一个中缀表达式1+2*3-4
怎么把它转成后缀呢?

1.我们还是从头去遍历这个表达式,如果遇到的是操作数,就输出

2.如果遇到的是的是操作符,那这时要分情况进行分析:

2.1 如果此时栈为空,就让该操作符进栈; 

2.2 如果遇到的是操作符,且此时栈不为空,则取栈顶的操作符与当前操作符比较优先级,如果比栈顶操作符优先级高,就让该操作符进栈,为什么是进栈而不是拿它进行运算呢?
因为后面有可能还有优先级更高的,所以先进栈。

3. 继续取下一个进行判断是操作数还是操作符。 如果比栈顶操作符优先级低或者相等,则出栈顶的操作符输出(即此时栈顶的这个操作符可以进行运算了) , 如果优先级更高那就继续入栈

4. 然后再去判断栈是否为空,不为空再拿当前操作符和栈顶操作符比较,进行相应操作,为空就入栈。

 5.遍历结束后,如果栈不为空,将剩余操作符输出。

此时,就得到对应的后缀表达式了。 

#include <iostream>
#include <stack>
#include <string>
using namespace std;

int Greater(char x, char y)
{
    int flag1 = 0, flag2 = 0;
    switch (x)
    {
        case '+':
            flag1 = 1;
            break;
        case '-':
            flag1 = 1;
            break;
        case '*':
            flag1 = 2;
            break;
        case '/':
            flag1 = 2;
            break;
    }

    switch (y)
    {
        case '+':
            flag2 = 1;
            break;
        case '-':
            flag2 = 1;
            break;
        case '*':
            flag2 = 2;
            break;
        case '/':
            flag2 = 2;
            break;
    }
    return flag1 - flag2;
}

int main() 
{
    stack<char> st;
    string s,ans;
    getline(cin,s);
    int i = 0;

    while(i<s.length())
    {
        if(s[i] >='a' && s[i] <='z')//值直接输出
            ans += s[i++];
        else//运算符
         {
            if(st.empty())//为空直接入栈
                st.push(s[i++]);
            else//栈里有运算符
            {
                while(!st.empty() && Greater(s[i], st.top()) <= 0)//栈不为空且当前运算符优先级小于等于栈里的运算符
                {
                    ans += st.top();
                    st.pop();
                }

                if(st.empty() || Greater(s[i], st.top()) == 1)//刚刚可能进行了一系列出栈操作,栈可能为空
                {
                    st.push(s[i]);
                    i++;
                }
            }
         }
    }
    
    while(!st.empty())//最后把栈里运算符全都输出出来
    {
        ans += st.top();
        st.pop();
    }

    cout << ans;
}
// 64 位输出请用 printf("%lld")

如果是带括号的情况呢? 

遇到(,我们认为它的优先级很低,但是我们不拿(做比较,直接让它入栈 ,然后下一个操作符也直接让它入栈,那继续往后走遇到)怎么办,们也认为)的优先级很低,遇到右括号直接把栈里到左括号为止的操作符全都弹出,再把(pop掉,其实就相当于在()里又进行了一次表达式的转换.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值