leetcode——基础计算器(中等)


前言

基础运算器,没有括号,只有加减乘除,运算数字不一定是只有一位的0~9,可能是多位。在提交了7遍之后,终于通过了。。。(大哭)


提示:本题思路及其简单直接,关键就是一些编程技巧,用得好可以简化代码

一、题目是什么?

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。整数除法仅保留整数部分。

示例 1:

输入:s = “3+2*2”
输出:7
示例 2:

输入:s = " 3/2 "
输出:1
示例 3:

输入:s = " 3+5 / 2 "
输出:5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/basic-calculator-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

注:虽然示例给的是个位数,但是题目要求是对于十进制数都可以的,要考虑如何把字符串转化为数字。

二、解答

1.我的解答

分析:
先乘除,后加减。运算符号和数字分别压栈
乘除:
遍历一遍字符串:1、遇到space,直接跳过 2、遇到数字,判断它到底有几位,利用ASCLL将字符串转化为long int 整型(之前用过int 整型,但是在测试中出现了溢出现象) 3、遇到加减,符号压栈 3、遇到*\,将这个符号前后两个数运算,将计算结果代替原来的top()。

加减:乘除中,我是在字符串从前往后这么遍历的,这就导致一个问题,之后进行加减运算的时候,还要把栈中元素的顺序reverse。
所以我在想,从后往前,会不会节省内存,这样就不用在reverse栈了。

class Solution {
public:
    //第一遍先算乘除,第二遍算加减
    //
    int calculate(string s) {
    stack<long int> symbol;//储存运算符号
    stack<int> num;
    stack<long int> symbol1;//储存运算符号
    stack<int> num1;
    int n=s.size();
    long int temp=0;//溢出
    long int help=0;
    int i=0,j=-1;
    //先乘除
    while(i<n){
        if(s[i]==32) i++;
        
        else if(s[i]>='0'&&s[i]<='9') {
            if(j==i-1&&j!=-1){
            temp=num.top();
            num.pop();
            temp=temp*10+s[i]-'0';
            num.push(temp);
            j=i;
            i++;//考虑一下十位数
            }
            else{
            num.push(s[i]-'0');
            j=i;
            i++;
            }
            
        }
       
        else if(s[i]==43){//+
            symbol.push(1);
            i++;
        }
        
        else if(s[i]==45){//-
            symbol.push(-1);
            i++;
        }
       
        else if(s[i]==42){//*
        temp=num.top();
        num.pop();
        j=1;
        while(s[i+j]==32) j++;
        i=i+j;//开始下一个数
        help=0;
        while(s[i]>='0'&&s[i]<='9'){
        help=help*10+s[i]-'0';
        i++;
        }
        temp=temp*help;
        num.push(temp);
        }
        else if(s[i]==47){// /
        temp=num.top();
        num.pop();
        j=1;
        while(s[i+j]==32) j++;
        i=i+j;//开始下一个数
        help=0;
        while(s[i]>='0'&&s[i]<='9'){
        help=help*10+s[i]-'0';
        i++;
        }
        temp=temp/help;
        num.push(temp);
        }
        else{
            cout<<"wrong!"<<endl;
        }
    }
    while(!symbol.empty()){
        symbol1.push(symbol.top());
        symbol.pop();
    }
    while(!num.empty()){
        num1.push(num.top());
        num.pop();
    }
    //后加减
    while(!symbol1.empty()){
        if(symbol1.top()==1){
            temp=num1.top();
            num1.pop();
            temp=temp+num1.top();
            num1.pop();
            num1.push(temp);
            symbol1.pop();
        }
        else if(symbol1.top()==-1){
            temp=num1.top();
            num1.pop();
            temp=temp-num1.top();
            num1.pop();
            num1.push(temp);
            symbol1.pop();
        }
        else{
            cout<<"wrong!"<<endl;
        }
    }
    temp=num1.top();
    return temp;

    }
};

2.官方

由于乘除优先于加减计算,因此不妨考虑先进行所有乘除运算,并将这些乘除运算后的整数值放回原表达式的相应位置,则随后整个表达式的值,就等于一系列整数加减后的值。

基于此,我们可以用一个栈,保存这些(进行乘除运算后的)整数的值。对于加减号后的数字,将其直接压入栈中;对于乘除号后的数字,可以直接与栈顶元素计算,并替换栈顶元素为计算后的结果。

具体来说,遍历字符串 ss,并用变量 \textit{preSign}preSign 记录每个数字之前的运算符,对于第一个数字,其之前的运算符视为加号。每次遍历到数字末尾时,根据 \textit{preSign}preSign 来决定计算方式:

加号:将数字压入栈;
减号:将数字的相反数压入栈;
乘除号:计算数字与栈顶元素,并将栈顶元素替换为计算结果。
代码实现中,若读到一个运算符,或者遍历到字符串末尾,即认为是遍历到了数字末尾。处理完该数字后,更新 preSign 为当前遍历的字符。

遍历完字符串 s 后,将栈中元素累加,即为该字符串表达式的值。

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/basic-calculator-ii/solution/ji-ben-ji-suan-qi-ii-by-leetcode-solutio-cm28/
来源:力扣(LeetCode)

优点:将加减统一为加(减去相反数)。减少内存和时间。

class Solution {
public:
    int calculate(string s) {
        vector<int> stk;
        char preSign = '+';
        int num = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            if (isdigit(s[i])) {//专门判断数字的函数
                num = num * 10 + int(s[i] - '0');
            }
            if (!isdigit(s[i]) && s[i] != ' ' || i == n - 1) {//判断符号,多个判断条件一起考虑
            //排除space,确定终止条件
                switch (preSign) {
                    case '+':
                        stk.push_back(num);
                        break;
                    case '-':
                        stk.push_back(-num);
                        break;
                    case '*':
                        stk.back() *= num;
                        /*temp=stk.top();
                          stk.pop();
                          temp=temp*num;
                          stk.push(temp);
                        */
                        break;
                    default:
                        stk.back() /= num;
                }
                preSign = s[i];
                num = 0;
            }
        }
        return accumulate(stk.begin(), stk.end(), 0);//另一个高级函数,计算栈里面的元素之和
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/basic-calculator-ii/solution/ji-ben-ji-suan-qi-ii-by-leetcode-solutio-cm28/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

总结

之前学习数据结构的时候,在栈的应用那一节,详细讲了如何通过栈进行四则运算,记得还有专门的后缀,前缀写法。现在都已经忘得七七八八了,只记得如果遇到右括号,就一直弹栈,直到弹到第一个左括号为止。
但是面对千奇百怪的问题变形,记得理论什么的可能也没多大用了,一些基本的思想,包括实践的经验还有待慢慢积累练习。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值