224. Basic Calculator

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 .

Example 1:

Input: "1 + 1"
Output: 2

Example 2:

Input: " 2-1 + 2 "
Output: 3

Example 3:

Input: "(1+(4+5+2)-3)+(6+8)"
Output: 23

Note:

You may assume that the given expression is always valid.
Do not use the eval built-in library function.

方法1:

laioffer: https://www.youtube.com/watch?v=9c0WHgIsk5g

思路:

首先考虑没有括号的情况:因为题目限制了只有加减,没有括号优先级从左到右。初始化用第一个数字,之后需要遍历所有字符,对每一个数字,记录它本身和它之前的符号,如果是‘-’就substract,如果是‘+’就add。

那么加上括号会改变什么?先进来的符号如果跟着parentheses就有可能被后执行。模拟先进后出需要借用stack。同时记录符号的优先级,1,2, 3, …,有左括号的话,将要进来的符号优先级++,右括号将未来的符号优先级–。所以对于一个operator/operand组合,我们要做的是:1. 用operand之前出现的一个operator来决定sign,往之前的result上累加。除非之前紧邻的是一个“(”, sign恢复默认值1,先不要累加。2. 每当遇到了“(”,我们将前一个operator入栈,sign = 1, 并将之前的result推入另一个栈,result清零。3. 每当遇到了“)", 说明后面的优先级降低,此时由于遵从由左到右的顺序,operator栈顶如果不为空将有更高优先级,同时从operator栈中pop符号,从operand栈中pop数字继续累加。

在这个过程中operand和operator由两个栈来维护并始终保持着同样的大小,每次需同时弹入弹出。

优先级这个信息并不需要直白的记录,可以用以下方法,由“(”,“)”,两个条件段自动控制优先级。

易错点

  1. 数字可以不止一位,即使栗子里面故意不提醒你。所以需要一个单独的变量num用来累计连续数字。这个数字只有当遇到下一个不为数字的字符时,可以当作结果被累计。
  2. 注意“)”这个段落及其容易错,此时的op.top()到底是谁的operator?是在result被清零前被入栈的,因此属于当前括号内累加的结果result。这个result * op.top() 应该向谁继续累加?和op.top()被同时推入栈的上一个result,也就是当前的od.top()。而且取出后别忘弹栈。
  3. 最后一次result += sign * num 为什么重要:当expression以non-digit结尾(反括号或者whitespace),最后一个operand没有机会进入else去累加到结果上。
  4. (c - ‘0’)这个地方括号也很重要:如果input就是INT_MAX,上来直接加c会overflow。

Complexity

Time complexity: O(n)
Space complexity: O(n)

class Solution {
public:
    int calculate(string s) {
        int result = 0;
        int sign = 1;
        int num = 0;
        stack<int> op;
        stack<int> od;
        for (char c: s){
            if (isdigit(c)){
                num = num * 10 +  (c - '0');
            }
            else {
                result += sign * num;
                num = 0;
                if (c == '+'){
                    sign = 1;
                }
                else if (c == '-'){
                    sign = -1;
                }
                else if (c == '('){
                    op.push(sign);
                    od.push(result);
                    sign = 1;
                    result = 0;
                }
                else if (c == ')'){
                    // 5 = 10 - (5 * 1)
                    // 5 =  - (5 * 1) + 10
                    result = result* op.top() + od.top();
                    op.pop();
                    od.pop();
                }
            }
            
        }
        result += sign * num;
        return result;
    }
};

// "(1+(4+5+2)-3)+(6+8)"
//      i

//result = 9
// sign =  -1
// op = {1, }
// od = {0, }

方法2: recursion

参考 772. Basic Calculator III
grandyang: http://www.cnblogs.com/grandyang/p/4570699.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值