LeetCode224 基本计算器

题目描述

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

给定的字符串表达式由数字、‘+’、‘-’、‘(’、‘)’、‘ ’组成。

比如给定字符串"1 +1", 函数需要返回结果2。

解法:双栈

首先看到这个题应该会想到后缀表达式的计算过程,设置一个nums栈存放数字,遇到运算符就取nums栈顶两个元素计算,然后放回栈中。但是题目给的是一个中缀表达式,计算需要考虑优先级,因此可以增加一个ops栈来存放操作符,而与后缀表达式不同的是,计算过程中根据不同的ops执行不同的操作步骤

遍历一个字符串表达式的具体过程如下:

数字: 直接放入nums栈。 这里在代码中需要注意,有些数字可能是由好几位组成,比如123+123, 读取的时候一定要注意将123整体读进去。

左括号: 直接入ops栈。 左括号表示括号内计算的开始,直接入栈,不用执行任何操作。

右括号:按照后缀表达式的方法计算,直到遇到左括号。 右括号与之对应的左括号构成了一个子式,这个子式在遇到右括号时就可以开始计算。

加减: 遇到加减,先判断ops栈顶是否还是加减,如果是的话,说明nums中有数字还没有计算,按照后缀表达式的方法计算就好,计算完成后将这一位的加减入栈。

在实现过程中还有一些细节需要注意:

  • 所给表达式中可能存在一些空格,需要先将表达式中的空格清除。
  • 表达式首位可能是负号,这样操作符出栈时,nums栈也出栈,可能会报栈为空的错误,所以可以往表达式首位放一个0,避免分情况讨论。
  • 与第二点类似,可能出现连续符号的情况,比如1+(-2),为避免报错,可以在-号入栈时,nums中加一个0。
代码:
class Solution {
public:
    void cleanSpace(string& s){
        int pos = s.find(" ");
        while (pos != -1) {
            s.replace(pos, 1, "");
            pos = s.find(" ");
        }
    }

    void calc(stack<int>& nums, stack<char>& ops){
        if(nums.size()<2 || ops.empty()) return;
        int a=nums.top();
        nums.pop();
        int b=nums.top();
        nums.pop();
        char op=ops.top();
        ops.pop();
        nums.push(op=='+'?a+b:b-a);
    }

    int calculate(string s) {
        stack<int> nums;
        stack<char> ops;

        cleanSpace(s);
        // 清除空格

        nums.push(0);

        int n=s.size();

        for(int i=0; i<n; i++){
            char c=s[i];
            if(c=='('){
                ops.push(c);
            }
            else if(c==')'){
                // 右括号的话计算到碰到左括号
                while(!ops.empty()){
                    if(ops.top()!='('){
                        // 计算没有遇到终点
                        calc(nums, ops);
                    }
                    else{
                        // 遇到左括号 运算结束
                        ops.pop();
                        // 左括号弹出
                        break;
                        // 跳出循环
                    }
                }
            }
            else if(isdigit(c)){
                // 如果是数字
                // 需要考虑一下连续数字的情况
                int num=0;
                int j=i;
                while(j<n && isdigit(s[j])){
                    // j在数组范围内而且j位置处是数字如果j开始是数字
                    num = num*10 + (s[j]-'0');
                    j++;
                }
                // 计算出一整串数字 最后j停留在数字的下一位上
                i=j-1;
                nums.push(num);
            }
            else{
                // 如果是正负号 看看它的左边有没有左括号
                if(i>0 && (s[i-1]=='(' || s[i-1]=='+' || s[i-1]=='-')){
                    nums.push(0);
                }
                // 正负号别着急入栈 看看ops栈顶是不是+-,如果是的话先计算
                while(!ops.empty() && ops.top()!='('){
                    calc(nums, ops);
                }
                ops.push(c);
            }
        }

        if(!ops.empty()){
            calc(nums, ops);
        }

        return nums.top();
    }

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值