224. 基本计算器

224. 基本计算器

LeetCode题目:224. 基本计算器

思路分析

  • 题目大意是给你一个简单字符串s,计算其值。

  • 有几个注意点:

    • 运算符只有+ - ( )
    • 字符串s中有空格。
    • 没说数字是个位数,也就是1+123这样的表达式是合法的。
    • 可能存在 负数 ,也就是-2+1这样的表达式是合法的。
  • 刚开始审题不认真,想用以前本科时期学习时用的 栈 + 逆波兰表达式

  • 其实注意到了上面的几个注意点就好写了。

我的解题方法

  • 首先,对字符串进行预处理:

    • 1.去除所有空格
    • 2.将字符串s改成(0+s)的形式,记为S(后面会解释为什么)。
    • 3.将S中的连续的两个+或者-合并。
      • ++合并成+
      • +-合并成-
      • -+合并成-
      • --合并成+
  • 解释上述三点:

    • 1.空格没用,所以提前删掉。
    • 2.后面解释。
    • 3.因为存在 负数 ,因此可能有这样的情况1 + -2 - +4的情况,经过1和3处理后会变成1-2-4
  • 定义两个栈:

    • stack<char> stk_op存放运算符。
    • stack<char> stk_num存放数字。
  • 因为栈是 先进后出 ,因此需要 倒序 遍历S。

    • 比如1-2+4,如果是正序遍历的话:stk_op中会存放- +stk_num中会存放1 2 4,运算顺序变成了2+4-1了,显然不对。
    • 如果是倒序遍历的话,stk_op中会存放+ -stk_num中会存放4 2 1,运算顺序是1-2+4
  • 假设当前遍历到Spos位置,分为如下几种情况:

    • S[pos] = ')',此时将’)'压入stk_op中。
    • S[pos] = '(',此时,将stk_opstk_num中的运算符和数字进行运算,直到stk_op.top()=')'为止。
      • 栗子:比如运算(1+(2-3)+4),显然要优先算(2-3),[倒序]遇到’)‘显然不能计算,直到遇到’(’,那么此时stk_op中是)+)-stk_num中是432,将stk_numstk_op中的数字进行运算,直到stk_op.top()=')。也就是运算2-3
    • 遇到数字0~9,将数字(不一定是个位数)获取,加入栈stk_num中。
  • 解释2.后面解释。

    • 上面的假设是基于S中有()而进行的,如果没有(),上面的规则是没有办法进行的。因此,我们可以将s变成(s)就能保证一定有一对()
    • 现在的s(s),那么还有一种情况(-2+1),我们可以添加0+即可解决,此时S=(0±2-1),经过步骤3即可变成S=(0-2-1)。因此,最终S记为(0+s)

有了上述思路,可以写出AC代码:

class Solution {
public:
    int calculate(string s) {
        string S = "(";
        s = "0+" + s;
        int j = 0;
        while (j < s.size()){
            if (s[j] == ' '){
                j ++;
            }else if (s[j] == '+'){
                if (j+1 != s.size()){
                    if (s[j+1] == '+'){
                        j = j + 2;
                        S.push_back('+');
                    }else if (s[j+1] == '-'){
                        j = j + 2;
                        S.push_back('-');
                    }else{
                        S.push_back('+');
                        j ++;
                    }
                }else{
                    S.push_back('+');
                    j ++;
                }
            }else if (s[j] == '-'){
                if (j+1 != s.size()){
                    if (s[j+1] == '+'){
                        j = j + 2;
                        S.push_back('-');
                    }else if (s[j+1] == '-'){
                        j = j + 2;
                        S.push_back('+');
                    }else{
                        S.push_back('-');
                        j ++;
                    }
                }else{
                    S.push_back('+');
                    j ++;
                }
            }else{
                S.push_back(s[j++]);
            }
        }
        S.push_back(')');

        stack<char> stk_op;
        stack<int> stk_num;
        int n = S.size();
        int pos = n - 1;
        while (pos != -1){
            if (S[pos] == ')'){
                stk_op.push(')');
                pos --;
            }else if (S[pos] == '('){
                while (!stk_op.empty() && !stk_num.empty()){
                    if (stk_op.top() == ')'){
                        stk_op.pop();
                        break;
                    }else{
                        int num1 = stk_num.top();
                        stk_num.pop();
                        int num2 = stk_num.top();
                        stk_num.pop();
                        int op = stk_op.top();
                        stk_op.pop();
                        int ans = 0;
                        if (op == '+'){
                            ans = num1 + num2;
                        }else{
                            ans = num1 - num2;
                        }
                        stk_num.push(ans);
                    }
                }
                pos --;
            }else if (S[pos] == '+' || S[pos] == '-'){
                stk_op.push(S[pos]);
                pos --;
            }else{
                int index = pos;
                while (index != 0 && '0' <= S[index] && S[index] <= '9'){
                    index --;
                }
                string s_digit = S.substr(index+1, pos-index);
                int digit = stoi(s_digit);
                stk_num.push(digit);
                pos = index;
            }
        }
        return stk_num.top();
    }
};
  • 很不幸,写了有96行代码。
  • 使用了std:string中的函数stoi将一个字符串转化成整数。

执行用时:20 ms, 在所有 C++ 提交中击败了50.04%的用户
内存消耗:10.2 MB, 在所有 C++ 提交中击败了35.76%的用户

  • 复杂度分析:
    • 时间复杂度:O(n),准确的是O(2*n),遍历一遍,计算一遍。
    • 空间复杂度:O(n),使用了两个栈。

LeetCode官方题解

  • 运算符只有+ - ( ),也就是说数字本身不会因为乘除而变化,只会因为()的出现而改变符号。
  • 维护一个栈ops,这个栈的栈顶记录了当前位置数字的 正负号
    (1+(2-3)+4-(5-6))
    ++ ++ -- + --++++
    
  • 那么我们可以整理出来规则:
    • 当遍历到-,那么当前的符号要变成栈顶相反的符号。
    • 遍历到+,当前符号是栈顶的符号。
    • 当遇到(,将当前符号压栈。
    • 遍历到),将栈顶符号弹栈。

因此,我们可以正序计算出结果。

class Solution {
public:
    int calculate(string s) {
        stack<int> ops;
        ops.push(1);
        int sign = ops.top();
        int pos = 0;
        int n = s.size();
        int ret = 0;
        while (pos < n){
            if (s[pos] == ' '){
                pos ++;
            }else if (s[pos] == '-'){
                sign = -ops.top();
                pos ++;
            }else if (s[pos] == '+'){
                sign = ops.top();
                pos ++;
            }else if (s[pos] == '('){
                ops.push(sign);
                pos ++;
            }else if (s[pos] == ')'){
                ops.pop();
                pos ++;
            }else{
                long num = 0;
                while (pos != n && '0' <= s[pos] && s[pos] <= '9'){
                    num = num * 10 + s[pos] - '0';
                    pos ++;
                }
                ret += sign * num;
            }
        }
        return ret;
    }
};

执行用时:12 ms, 在所有 C++ 提交中击败了71.50%的用户
内存消耗:7.8 MB, 在所有 C++ 提交中击败了90.08%的用户

  • 复杂度分析:
    • 时间复杂度:O(n),一遍遍历。
    • 空间复杂度,O(n),使用了一个栈ops。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值