美文网首页
224. Basic Calculator 笔记

224. Basic Calculator 笔记

作者: 赵智雄 | 来源:发表于2017-07-14 22:33 被阅读119次

Implement a basic calculator to evaluate a simple expression string.

The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces .
You may assume that the given expression is always valid.
Some examples:

"1 + 1" = 2
" 2-1 + 2 " = 3
"(1+(4+5+2)-3)+(6+8)" = 23```
就是把这个字符串解析成一个式子然后算出结果。运算只有加减法,也没有负数,优先级比较好搞。有括号先算括号里面的。C语言书里头讲过可以用栈。这里的括号,我自然地想到了递归。“)”是递归的终止条件。遇到右括号就相当于括号里的东西处理完返回括号里头的结果。为了方便处理,把输入的字符串最后加上了一个“)”,这样递归的终止条件就不用再加一个判断字符串结束了。
从头开始读字符串,边读边解析。分几情况:
1,正负号,整形op表示符号。减法乘以-1也转化为加法。
2,数字,解析出来压到存运算数的vector里去。
3,左括号,开始递归调用这个函数,表示要先算括号里面的。
括号里的运算出结果就把它压到运算数的向量里头。(运算数的来源就三种,从字符串解析出来,和括号里的值算出来,运算数的vector进行运算的结果。)
4,右括号,说明函数该就结束了。
只要现在存这两个运算数,就可以做运算了。
代码如下:(递归)
```cpp
class Solution {
public:
    int calculate(string s) {
        //递归
        int index = 0;
        s += ')';
        int res = calucateBrackets(s,index);
        return res;
    }
private:
    //计算括号里面的值
    int calucateBrackets(string &s,int &index)
    {
        vector<int> num; //数
        int op = 0; //运算符  +1 -1 
        for(index; s[index] != ')'; index++)
        {
            if(s[index] == ' ')//空格,跳过
                continue;
            if(s[index] == '+')//正负号
            {
                op = 1;
                continue;
            }
            else if(s[index] == '-')
            {
                op = -1;
                continue;
            }
            if(s[index] >= '0' && s[index] <= '9')//数字
            {
                int value = parseInt(s,index);
                num.push_back(value);//把这数放进去
            }
            else if(s[index] == '(')//如果是左括号,递归算括号里面的
            {
                index++;
                int res = calucateBrackets(s,index);
                num.push_back(res);
            }
            if(num.size() == 2)
            {
                int a = num[0];
                int b = num[1];
                num.clear();
                num.push_back(a + op*b);
            }
        }
        return num[0];
    }
    //连读一个数
    int parseInt(string &s, int &index)
    {
        int res = 0;
        while(s[index] >= '0' && s[index] <= '9')
        {
            res*= 10;
            res+= (s[index] - '0');
            index++;
        }
        index--;
        return res;
    }
};

也可以不用递归算这个。
if else 大法好。。。
两个栈,一个存运算符,一个存运算数。“+”存1,“-”存-1,“(”存0,当个分界符。遇到“)”就弹栈,算,算到运算符栈有个0相当于算完一个括号。用栈的话是从后往前算。要是前头有负号就会出错了。(就像1-2+3,从后往前算相当于1-(2+3)所以,遇到负号就把它算掉。。)
代码如下:(非递归)

class Solution {
public:
    int calculate(string s) {
        int index = 0;
        if(s.size() == 0)
            return 0;
        vector<int> num; //数
        vector<int> op; 
        op.push_back(0);
        //操作符   + 1  - -1  ( 2  
        //stack<int> num; //数
        //stack<int> op; //操作符   + 1  - -1  ( 2  
        for(index ; index < s.size(); index++)
        {
            if(s[index] == '+')
            {
                op.push_back(1);
            }
            else if(s[index] == '-')
            {
                op.push_back(-1);
            }
            else if(s[index] >= '0' && s[index] <= '9')//数字
            {
                int value = parseInt(s,index);
                num.push_back(value);//
                if(num.size() >= 2 && op[op.size()-1] != 0)
                {
                    int b = num[num.size()-1];
                    num.pop_back();
                    int a = num[num.size()-1];
                    num.pop_back();
                    int c = op[op.size()-1];
                    op.pop_back();
                    num.push_back(a+b*c);
                    //calc(num, op);
                }
            }
            else if(s[index] == '(')//左括号压栈
            {
                op.push_back(0);
            }
            else if(s[index] == ')')//右括号,一直算啊算,知道算到左括号位置
            {
                while(op[op.size()-1] != 0)
                {
                    int b = num[num.size()-1];
                    num.pop_back();
                    int a = num[num.size()-1];
                    num.pop_back();
                    int c = op[op.size()-1];
                    op.pop_back();
                    num.push_back(a+b*c);  
                    //calc(num, op);
                }
                op.pop_back();
                if(num.size() >= 2 && op[op.size()-1] != 0)
                {
                    int b = num[num.size()-1];
                    num.pop_back();
                    int a = num[num.size()-1];
                    num.pop_back();
                    int c = op[op.size()-1];
                    op.pop_back();
                    num.push_back(a+b*c);
                    //calc(num, op);
                }
            }
        }
        while(num.size() != 1)
        {
            int b = num[num.size()-1];
            num.pop_back();
            int a = num[num.size()-1];
            num.pop_back();
            int c = op[op.size()-1];
            op.pop_back();
            num.push_back(a+b*c);
            //calc(num, op);
        }
        return num[0];
    }
private:
    //连读一个数
    int parseInt(string &s, int &index)
    {
        int res = 0;
        while(s[index] >= '0' && s[index] <= '9')
        {
            res*= 10;
            res+= (s[index] - '0');
            index++;
        }
        index--;
        return res;
    }
};

还有个坑一点的地方。就是解析数字这个我弄成了一个函数,最开始传参传的是string,每次传参相当于复制,所以遇到一个特别长的测试用例时候就特别慢,超时了。改成引用传参就跑过去了。

相关文章

网友评论

      本文标题:224. Basic Calculator 笔记

      本文链接:https://www.haomeiwen.com/subject/mhgohxtx.html