224. 基本计算器

224. 基本计算器(困难)
答案整理 加深记忆 便于复习!
python eval()函数还没完全看懂。。。

题目描述

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

示例 1:

输入:s = “1 + 1”
输出:2

示例 2:

输入:s = " 2-1 + 2 "
输出:3

示例 3:

输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23

提示:

1 <= s.length <= 3 * 105
s 由数字、’+’、’-’、’(’、’)’、和 ’ ’ 组成
s 表示一个有效的表达式

方法:括号展开 + 栈

由于字符串除了数字与括号外,只有加号和减号两种运算符。因此,如果展开表达式中所有的括号,则得到的新表达式中,数字本身不会发生变化,只是每个数字前面的符号会发生变化。

因此,我们考虑使用一个取值为 {−1,+1} 的整数 sign 代表「当前」的符号。根据括号表达式的性质,它的取值:

  • 与字符串中当前位置的运算符有关;
  • 如果当前位置处于一系列括号之内,则也与这些括号前面的运算符有关:每当遇到一个以 − 号开头的括号,则意味着此后的符号都要被「翻转」。

考虑到第二点,我们需要维护一个栈 ops,其中栈顶元素记录了当前位置所处的每个括号所「共同形成」的符号。例如,对于字符串 1+2+(3-(4+5)):

  • 扫描到 1+2 时,由于当前位置没有被任何括号所包含,则栈顶元素为初始值 +1;
  • 扫描到 1+2+(3 时,当前位置被一个括号所包含,该括号前面的符号为 ++ 号,因此栈顶元素依然 +1+1;
  • 扫描到 1+2+(3-(4 时,当前位置被两个括号所包含,分别对应着 + 号和 − 号,由于 + 号和 − 号合并的结果为 − 号,因此栈顶元素变为 -1。

在得到栈 ops 之后, sign 的取值就能够确定了:如果当前遇到了 + 号,则更新 sign ← ops.top();如果遇到了遇到了 − 号,则更新sign← - ops.top()。

然后,每当遇到 ( 时,都要将当前的 sign 取值压入栈中;每当遇到 ) 时,都从栈中弹出一个元素。这样,我们能够在扫描字符串的时候,即时地更新 ops 中的元素。

C++:

class Solution 
{
public:
	int calculate(string s) 
	{
		stack<int> ops;
		ops.push(1);
		int sign = 1;//1代表加,下面如果是减,就变成-1,ret += sign*num这句代码实现了加法是加(数)本身,减法是加(数x负一)
		int ret = 0;
		int n = s.length();
		int i = 0;
		while (i < n)
		{
			if (s[i] == ' ') i++;
			//利用正负符号将括号击穿,直接一遍就计算出来了
			//下面几句话要多加品味
			else if (s[i] == '+') { sign = ops.top(); i++; }
			else if (s[i] == '-') { sign = -ops.top(); i++; }
			else if (s[i] == '(') { ops.push(sign); i++; }//遇到左括号时就将左括号前一个运算符(记为sign1)压入栈内,
														  //接下来左括号后右括号前的数据都将受到该符号的影响,因为在此之后ops.top()返回的都是sign1,假设括号中间还有负号,负负得正,符合实际。             
			else if (s[i] == ')') { ops.pop(); i++; }//一旦遇到该左括号对应的右括号,sign1就被弹出栈了,sign1的使命就结束了。
			else
			{
				long num = 0;
				//while的作用是把可能有多位的字符串转为数字
				while (s[i] >= '0'&&s[i] <= '9')//一个数字可能有很多位,比如有三位,要先单独将该三位字符串转为int型数字
				{
					//好比将字符 ‘290’转成数字290,先解析2,再解析9时,将2*10+9=29;再解析0时,将29*10+0=290;这样,就完成了字符’290‘到数字290的转变。
					num = num * 10 + (s[i] - '0');//s[i] - '0' 字符转int
					i++;
				}
				ret += sign*num;
			}
		}
		return ret;
	}
};

复杂度分析

时间复杂度:O(n),其中 n 为字符串 s 的长度。需要遍历字符串 s 一次,计算表达式的值。

空间复杂度:O(n),其中 n 为字符串 s 的长度。空间复杂度主要取决于栈的空间,栈中的元素数量不超过 n。

使用python eval()函数

直接使用python eval()函数,报错如下:
在这里插入图片描述

直接eval(s)的话会报MemoryError,考虑从内到外依次计算括号(目前还没太理解明白,下次再看)

class Solution:
    def calculate(self, s: str) -> int:
        while True:
            a=s.rfind('(')
            b=s.find(')',a)
            if a==-1:
                break
            s=s[:a]+str(eval(s[a:b+1]))+s[b+1:]
        return eval(s)

网友的疑惑,正好也解答了我的疑问

1

在这里插入图片描述

2

在这里插入图片描述

3

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙叙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值