9月7日算法学习笔记(栈)

1.逆波兰表达式求数值

描述:给定一个逆波兰表达式,求表达式的值。数据范围:表达式长度满足 1≤n≤104 1≤n≤104 ,表达式中仅包含数字和 + ,- , * , / ,其中数字的大小满足 ∣val∣≤200 ∣val∣≤200 。

这题其实就是一个后缀表达式,将数值压入栈,遇到操作符,就将最上面两个数出栈,计算完之后再压入栈。

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param tokens string字符串vector 
     * @return int整型
     */
    int evalRPN(vector<string>& tokens) {
        // write code here
        stack<string> stk;
        int n1, n2, res;
        for (string &s : tokens) {
            if (s == "+" || s == "-" || s == "*" || s == "/") {
                n2 = stoi(stk.top());
                stk.pop();
                n1 = stoi(stk.top());
                stk.pop();
                if (s == "+") res = n1 + n2;
                else if (s == "-") res = n1 - n2;
                else if (s == "*") res = n1 * n2;
                else res = n1 / n2;
                stk.push(to_string(res));
            } else stk.push(s);
        }
        return stoi(stk.top());
    }
};

2.点击消除

描述:牛牛拿到了一个字符串。
他每次“点击”,可以把字符串中相邻两个相同字母消除,例如,字符串"abbc"点击后可以生成"ac"。
但相同而不相邻、不相同的相邻字母都是不可以被消除的。
牛牛想把字符串变得尽可能短。他想知道,当他点击了足够多次之后,字符串的最终形态是什么?

输入描述:
一个字符串,仅由小写字母组成。(字符串长度不大于300000)

输出描述:
一个字符串,为“点击消除”后的最终形态。若最终的字符串为空串,则输出0。

这题其实用队列更好,但是既然是练习栈的算法,那么也继续用栈,将字符串压入栈,然后当栈顶值与该值相同时,就将栈顶出栈,达到消除的效果。但是要注意的是,将最后结果出栈的时候,是先进后出的,要达到题目的效果就得再搞一个栈,压入了再出栈。

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

int main() {
    stack<char> s;
    string s1;
    cin>>s1;
    for(int i=0;i<s1.size();i++){
        if(s.empty()){
            s.push(s1[i]);
        }
        else{
            if(s.top()==s1[i]){
                s.pop();
            }
            else{
                s.push(s1[i]);
            }
        }
    }
    if(s.empty()){
        cout<<0<<endl;
        return 0;
    }
    stack<char>s2;
    while(!s.empty()){
        s2.push(s.top());
        s.pop();
    }
    while(!s2.empty()){
        cout<<s2.top();
        s2.pop();
    }
    cout<<endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

3.表达式求值

描述:请写一个整数计算器,支持加减乘三种运算和括号。
数据范围:0≤∣s∣≤1000≤∣s∣≤100,保证计算结果始终在整型范围内
要求:空间复杂度: O(n)O(n),时间复杂度 O(n)O(n)

这题其实可以转化为上面第一题的问题,就是多了一个将中缀表达式转化为后缀表达式的过程。也可以用来两个栈分别存储数据和操作符,直接计算。

#include <stack>
#include <string>
class Solution {
  public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回表达式的值
     * @param s string字符串 待计算的表达式
     * @return int整型
     */
    void oprete(stack<char>& op, stack<int>& digital) {
        int right = digital.top();
        digital.pop();
        int left = digital.top();
        digital.pop();
        if (op.top() == '*') digital.push(left * right);
        if (op.top() == '+') digital.push(left + right);
        if (op.top() == '-') digital.push(left - right);
        op.pop();
    }
    int solve(string s) {
        int n = s.length();
        stack<char> op;
        stack<int> digital;
        for (int i = 0; i < n;) {
            if (s[i] - '0' >= 0 && s[i] - '0' <= 9) {
                int j;
                int num = 0;
                for (j = i; j < n; j++) {
                    if (s[j] - '0' >= 0 && s[j] - '0' <= 9) {
                        num = num * 10 + s[j] - '0';
                    } else break;
                }
                digital.push(num);
                i = j;
                continue;
            } else if (op.empty()) {
                op.push(s[i++]);
                continue;
            }
            if (s[i] == '(') {
                op.push(s[i++]);
                continue;
            } else if (s[i] == '-' || s[i] == '+') {
                while (!op.empty() && op.top() != '(')oprete(op, digital);
                op.push(s[i]);
            } else if (s[i] == '*') {
                while (op.top() == '*')oprete(op, digital);
                op.push(s[i]);
            } else {
                while (op.top() != '(')oprete(op, digital);
                op.pop();
            }
            i++;
        }
        oprete(op, digital);
        return digital.top();
    }
};

谢谢阅读!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值